diff --git a/CODEOWNERS b/CODEOWNERS index 7c6530eb16de9051510d7344025cf8b61c566c78..2cc43b65e4e8ed2079838a54d1f7a375d9daec51 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,18 +1,19 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - + +- Copyright (c) 2021-2022 Huawei Device Co., Ltd. +- Licensed under the Apache License, Version 2.0 (the "License"); +- you may not use this file except in compliance with the License. +- You may obtain a copy of the License at +* +- http://www.apache.org/licenses/LICENSE-2.0 +* +- Unless required by applicable law or agreed to in writing, software +- distributed under the License is distributed on an "AS IS" BASIS, +- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- See the License for the specific language governing permissions and +- limitations under the License. +*/ + zh-cn/device-dev/kernel/ @Austin23 zh-cn/device-dev/website.md @Austin23 zh-cn/device-dev/faqs/ @Austin23 @@ -129,243 +130,480 @@ zh-cn/device-dev/subsystems/subsys-toolchain-hdc-guide.md @Austin23 zh-cn/device-dev/subsystems/subsys-toolchain-hiperf.md @Austin23 zh-cn/device-dev/subsystems/subsys-xts-guide.md @Austin23 -zh-cn/application-dev/ability/ @RayShih -zh-cn/application-dev/ui/ @HelloCrease -zh-cn/application-dev/notification/ @RayShih -zh-cn/application-dev/windowmanager/ @ge-yafang -zh-cn/application-dev/webgl/ @ge-yafang -zh-cn/application-dev/media/ @zengyawen -zh-cn/application-dev/security/ @zengyawen -zh-cn/application-dev/connectivity/ @zengyawen -zh-cn/application-dev/connectivity/ipc-rpc-overview.md @qinxiaowang -zh-cn/application-dev/connectivity/ipc-rpc-development-guideline.md @qinxiaowang -zh-cn/application-dev/connectivity/subscribe-remote-state.md @qinxiaowang -zh-cn/application-dev/telephony/ @zengyawen -zh-cn/application-dev/dfx/ @zengyawen -zh-cn/application-dev/database/ @ge-yafang -zh-cn/application-dev/napi/drawing_guidelines.md @ge-yafang -zh-cn/application-dev/napi/rawfile_guidelines.md @HelloCrease +zh-cn/application-dev/ability/ @RayShih @littlejerry1 @gwang2008 @ccllee @chengxingzhen +zh-cn/application-dev/IDL/ @RayShih @littlejerry1 @gwang2008 @ccllee @chengxingzhen +zh-cn/application-dev/device-usage-statistics/ @RayShih @shuaytao @wangzhen107 @inter515 +zh-cn/application-dev/ui/ @HelloCrease @huaweimaxuchu @tomatodevboy @niulihua +zh-cn/application-dev/notification/ @RayShih @jayleehw @li-weifeng2 @currydavids +zh-cn/application-dev/windowmanager/ @ge-yafang @zhangqiang183 @zhouyaoying @zxg-gitee +zh-cn/application-dev/webgl/ @zengyawen @zhangqiang183 @wind_zj @zxg-gitee +zh-cn/application-dev/media/audio-overview.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/audio-playback.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/audio-recorder.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/audio-renderer.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/audio-stream-manager.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/audio-capturer.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/opensles-playback.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/opensles-capture.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/audio-interruptmode.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/audio-volume-manager.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/audio-routing-manager.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/video-playback.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/video-recorder.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/avsession-overview.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/avsession-guidelines.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/image.md @zengyawen @zhangqiang183 @wind_zj @zxg-gitee +zh-cn/application-dev/media/camera.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/media/remote-camera.md @zengyawen @liuyuehua1 @saga2020 @currydavids +zh-cn/application-dev/security/accesstoken-overview.md @zengyawen @nianCode @nianCode @jinhaihw +zh-cn/application-dev/security/accesstoken-guidelines.md @zengyawen @nianCode @nianCode @jinhaihw +zh-cn/application-dev/security/permission-verify-guidelines.md @zengyawen @nianCode @nianCode @jinhaihw +zh-cn/application-dev/security/permission-list.md @zengyawen @zengyawen @nianCode @nianCode @jinhaihw +zh-cn/application-dev/security/userauth-overview.md @zengyawen @gaoyong @niejiteng @jumozhanjiang +zh-cn/application-dev/security/userauth-guidelines.md @zengyawen @gaoyong @niejiteng @jumozhanjiang +zh-cn/application-dev/security/huks-overview.md @zengyawen @gaoyong @niejiteng @jumozhanjiang +zh-cn/application-dev/security/huks-guidelines.md @zengyawen @gaoyong @niejiteng @jumozhanjiang +zh-cn/application-dev/security/cryptoFramework-overview.md @zengyawen @gaoyong @niejiteng @jumozhanjiang +zh-cn/application-dev/security/cryptoFramework-guidelines.md @zengyawen @gaoyong @niejiteng @jumozhanjiang +zh-cn/application-dev/security/hapsigntool-overview.md @zengyawen @gaoyong @niejiteng @jumozhanjiang +zh-cn/application-dev/security/hapsigntool-guidelines.md @zengyawen @gaoyong @niejiteng @jumozhanjiang +zh-cn/application-dev/security/app-provision-structure.md @zengyawen @gaoyong @niejiteng @jumozhanjiang +zh-cn/application-dev/connectivity/net-mgmt-overview.md @zengyawen @zhang-hai-feng @jyh926 @gaoxi785 +zh-cn/application-dev/connectivity/http-request.md @zengyawen @zhang-hai-feng @jyh926 @gaoxi785 +zh-cn/application-dev/connectivity/websocket-connection.md @zengyawen @zhang-hai-feng @jyh926 @gaoxi785 +zh-cn/application-dev/connectivity/socket-connection.md @zengyawen @zhang-hai-feng @jyh926 @gaoxi785 +zh-cn/application-dev/connectivity/ipc-rpc-overview.md @RayShih @xuepianpian @zhaopeng_gitee @vagrant_world +zh-cn/application-dev/connectivity/ipc-rpc-development-guideline.md @RayShih @xuepianpian @zhaopeng_gitee @vagrant_world +zh-cn/application-dev/connectivity/subscribe-remote-state.md @RayShih @xuepianpian @zhaopeng_gitee @vagrant_world +zh-cn/application-dev/telephony/ @zengyawen @zhang-hai-feng @jyh926 @gaoxi785 +zh-cn/application-dev/dfx/hiappevent-overview.md @zengyawen @stone2050 @stesen @elsen-liu +zh-cn/application-dev/dfx/hiappevent-guidelines.md @zengyawen @stone2050 @stesen @elsen-liu +zh-cn/application-dev/dfx/hitracemeter-overview.md @zengyawen @stone2050 @stesen @elsen-liu +zh-cn/application-dev/dfx/hitracemeter-guidelines.md @zengyawen @stone2050 @stesen @elsen-liu +zh-cn/application-dev/dfx/hitracechain-overview.md @zengyawen @stone2050 @stesen @elsen-liu +zh-cn/application-dev/dfx/hitracechain-guidelines.md @zengyawen @stone2050 @stesen @elsen-liu +zh-cn/application-dev/dfx/errormanager-guidelines.md @littlejerry1 @ccllee @chengxingzhen @RayShih +zh-cn/application-dev/dfx/errormanager-guidelines.md @littlejerry1 @ccllee @chengxingzhen @RayShih +zh-cn/application-dev/key-features/multi-device-app-dev/ @lingminghw @crazyracing0726 +zh-cn/application-dev/database/ @ge-yafang @feng-aiwen @gong-a-shi @logic42 +zh-cn/application-dev/napi/native-window-guidelines.md @ge-yafang @zhangqiang183 @zhouyaoying @zxg-gitee +zh-cn/application-dev/napi/mindspore-lite-guidelines.md @ge-yafang @grbuzhidao @jianghui58 @auraxu +zh-cn/application-dev/napi/rawfile_guidelines.md @ningningW zh-cn/application-dev/background-agent-scheduled-reminder/ @RayShih -zh-cn/application-dev/background-task-management/ @RayShih -zh-cn/application-dev/work-scheduler/ @HelloCrease -zh-cn/application-dev/internationalization/ @HelloCrease -zh-cn/application-dev/device/usb-overview.md @ge-yafang -zh-cn/application-dev/device/usb-guidelines.md @ge-yafang -zh-cn/application-dev/device/device-location-overview.md @sun-yue14 -zh-cn/application-dev/device/device-location-info.md @sun-yue14 -zh-cn/application-dev/device/device-location-geocoding.md @sun-yue14 -zh-cn/application-dev/device/sensor-overview.md @HelloCrease -zh-cn/application-dev/device/sensor-guidelines.md @HelloCrease -zh-cn/application-dev/device/vibrator-overview.md @HelloCrease -zh-cn/application-dev/device/vibrator-guidelines.md @HelloCrease -zh-cn/application-dev/device/sample-server-overview.md @HelloCrease -zh-cn/application-dev/device/sample-server-guidelines.md @HelloCrease -zh-cn/application-dev/reference/arkui-js/ @HelloCrease -zh-cn/application-dev/reference/arkui-ts/ @HelloCrease -zh-cn/application-dev/reference/native-apis @RayShih -zh-cn/application-dev/reference/native-lib @RayShih -zh-cn/application-dev/reference/apis/js-apis-DataUriUtils.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-ability-errorCode.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-ability-wantConstant.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-application-ability.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-application-abilityConstant.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-abilityDelegatorRegistry.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-application-abilitystage.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-appmanager.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-configuration.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-configurationconstant.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-featureAbility.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-formbindingdata.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-formextension.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-formerror.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-formhost.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-formInfo.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-missionManager.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-formprovider.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-particleAbility.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-service-extension-ability.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-application-StartOptions.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-application-staticSubscriberExtensionAbility.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-uripermissionmanager.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-application-Want.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-wantAgent.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-dataAbilityHelper.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-Context.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-ability-context.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-application-abilityDelegator.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-application-abilityDelegatorArgs.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-application-abilityMonitor.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-abilityrunninginfo.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-abilitystagecontext.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-application-context.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-extension-context.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-extensionrunninginfo.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-formextensioncontext.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-application-MissionSnapshot.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-permissionrequestresult.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-processrunninginfo.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-service-extension-context.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-application-shellCmdResult.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-commonEvent.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-emitter.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-notification.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-reminderAgent.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-eventhub.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-Bundle.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-deviceUsageStatistics.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-zlib.md @RayShih -zh-cn/application-dev/reference/apis/js-apis-animator.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-mediaquery.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-prompt.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-router.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-display.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-screenshot.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-window.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-effectKit.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-application-WindowExtensionAbility.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-screen.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-windowAnimationManager.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-webgl.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-webgl2.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-audio.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-camera.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-image.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-media.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-medialibrary.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-i18n.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-intl.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-resource-manager.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-backgroundTaskManager.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-workScheduler.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-WorkSchedulerExtensionAbility.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-config-policy.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-enterprise-device-manager.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-abilityAccessCtrl.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-huks.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-useriam-userauth.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-system-cipher.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-data-ability.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-data-DataShareResultSet.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-data-ValuesBucket.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-data-dataSharePredicates.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-data-dataShare.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-application-DataShareExtensionAbility.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-distributed-data.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-data-distributedobject.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-data-preferences.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-data-storage.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-system-storage.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-data-rdb.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-settings.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-data-resultset.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-document.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-environment.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-fileio.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-filemanager.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-statfs.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-storage-statistics.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-volumemanager.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-contact.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-call.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-observer.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-radio.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-sim.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-sms.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-telephony-data.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-net-connection.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-http.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-request.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-socket.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-webSocket.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-bluetooth.md @bmeangel -zh-cn/application-dev/reference/apis/js-apis-nfcTag.md @bmeangel -zh-cn/application-dev/reference/apis/js-apis-nfcTech.md @bmeangel -zh-cn/application-dev/reference/apis/js-apis-tagSession.md @bmeangel -zh-cn/application-dev/reference/apis/js-apis-connectedTag.md @bmeangel -zh-cn/application-dev/reference/apis/js-apis-rpc.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-wifi.md @bmeangel -zh-cn/application-dev/reference/apis/js-apis-wifiext.md @bmeangel -zh-cn/application-dev/reference/apis/js-apis-accessibility.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-faultLogger.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-hiappevent.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-hichecker.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-hidebug.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-hilog.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-hitracechain.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-hitracemeter.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-inputmethod.md @bmeangel -zh-cn/application-dev/reference/apis/js-apis-inputmethodengine.md @bmeangel -zh-cn/application-dev/reference/apis/js-apis-pasteboard.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-screen-lock.md @bmeangel -zh-cn/application-dev/reference/apis/js-apis-system-time.md @bmeangel -zh-cn/application-dev/reference/apis/js-apis-wallpaper.md @bmeangel -zh-cn/application-dev/reference/apis/js-apis-timer.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-battery-info.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-brightness.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-device-info.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-device-manager.md -zh-cn/application-dev/reference/apis/js-apis-geolocation.md @sun-yue14 -zh-cn/application-dev/reference/apis/js-apis-inputconsumer.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-inputdevice.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-inputeventclient.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-inputmonitor.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-power.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-runninglock.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-sensor.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-system-sensor.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-system-parameter.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-thermal.md @qinxiaowang -zh-cn/application-dev/reference/apis/js-apis-update.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-usb.md @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-colorSpaceManager.mdd @ge-yafang -zh-cn/application-dev/reference/apis/js-apis-vibrator.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-appAccount.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-distributed-account.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-osAccount.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-convertxml.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-process.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-uri.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-url.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-util.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-arraylist.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-deque.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-hashmap.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-hashset.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-lightweightmap.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-lightweightset.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-linkedlist.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-list.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-plainarray.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-queue.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-stack.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-treemap.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-treeset.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-vector.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-worker.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-xml.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-testRunner.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-uitest.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-hisysevent.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-privacyManager.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-EnterpriseAdminExtensionAbility.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-uiappearance.md @HelloCrease +zh-cn/application-dev/background-task-management/ @ningningW @wangwenli_wolf @tangtiantian2021 @nan-xiansen +zh-cn/application-dev/work-scheduler/ @ningningW +zh-cn/application-dev/internationalization/ @ningningW @Buda-Liu @budda-wang @yangqing3 +zh-cn/application-dev/device/usb-overview.md @ge-yafang @jasonyujia @andeszhang @liuhonggang123 +zh-cn/application-dev/device/usb-guidelines.md @ge-yafang @jasonyujia @andeszhang @liuhonggang123 +zh-cn/application-dev/device/device-location-overview.md @RayShih +zh-cn/application-dev/device/device-location-info.md @RayShih +zh-cn/application-dev/device/device-location-geocoding.md @RayShih +zh-cn/application-dev/device/sensor-overview.md @ningningW @hellohyh001 @butterls @star-wind-snow-and-rain +zh-cn/application-dev/device/sensor-guidelines.md @ningningW @hellohyh001 @butterls @star-wind-snow-and-rain +zh-cn/application-dev/device/vibrator-overview.md @ningningW @hellohyh001 @butterls @star-wind-snow-and-rain +zh-cn/application-dev/device/vibrator-guidelines.md @ningningW @hellohyh001 @butterls @star-wind-snow-and-rain +zh-cn/application-dev/device/sample-server-overview.md @ningningW @hughes802 @zhangzhengxue @mamba-ting +zh-cn/application-dev/device/sample-server-guidelines.md @ningningW @hughes802 @zhangzhengxue @mamba-ting +zh-cn/application-dev/reference/arkui-js/ @HelloCrease @huaweimaxuchu @niulihua @tomatodevboy +zh-cn/application-dev/reference/arkui-ts/ @HelloCrease @huaweimaxuchu @niulihua @tomatodevboy +zh-cn/application-dev/reference/native-lib @zengyawen @gongjunsong @liwentao_uiw @BlackStone zh-cn/application-dev/quick-start/start-overview.md @ge-yafang -zh-cn/application-dev/quick-start/start-with-ets.md @ge-yafang -zh-cn/application-dev/quick-start/start-with-ets-low-code.md @ge-yafang -zh-cn/application-dev/quick-start/start-with-js.md @ge-yafang -zh-cn/application-dev/quick-start/start-with-js-low-code.md @ge-yafang -zh-cn/application-dev/quick-start/deveco-studio-user-guide-for-openharmony.md @ge-yafang -zh-cn/application-dev/quick-start/package-structure.md @RayShih -zh-cn/application-dev/quick-start/basic-resource-file-categories.md @RayShih -zh-cn/application-dev/quick-start/syscap.md @RayShih -zh-cn/application-dev/napi/napi-guidelines.md @RayShih -zh-cn/application-dev/napi/drawing-guidelines.md @ge-yafang -zh-cn/application-dev/napi/rawfile-guidelines.md @HelloCrease -zh-cn/application-dev/reference/apis/js-apis-buffer.md @zengyawen -zh-cn/application-dev/reference/js-service-widget-ui @HelloCrease -zh-cn/application-dev/website.md @zengyawen +zh-cn/application-dev/quick-start/start-with-ets-stage.md @ge-yafang +zh-cn/application-dev/quick-start/start-with-ets-fa.md @ge-yafang +zh-cn/application-dev/quick-start/start-with-js-fa.md @ge-yafang +zh-cn/application-dev/quick-start/application-package-overview.md @RayShih +zh-cn/application-dev/quick-start/application-package-structure-stage.md @RayShih +zh-cn/application-dev/quick-start/application-package-structure-fa.md @RayShih +zh-cn/application-dev/quick-start/har-structure.md @RayShih +zh-cn/application-dev/quick-start/multi-hap-objective.md @RayShih +zh-cn/application-dev/quick-start/multi-hap-build-view.md @RayShih +zh-cn/application-dev/quick-start/multi-hap-release-deployment.md @RayShih +zh-cn/application-dev/quick-start/multi-hap-rules.md @RayShih +zh-cn/application-dev/quick-start/multi-hap-principles.md @RayShih +zh-cn/application-dev/quick-start/application-package-install-uninstall.md @RayShih +zh-cn/application-dev/quick-start/application-configuration-file-overview-stage.md @RayShih +zh-cn/application-dev/quick-start/app-configuration-file.md @RayShih +zh-cn/application-dev/quick-start/module-configuration-file.md @RayShih +zh-cn/application-dev/quick-start/application-configuration-file-overview-fa.md @RayShih +zh-cn/application-dev/quick-start/app-structure.md @RayShih +zh-cn/application-dev/quick-start/deviceconfig-structure.md @RayShih +zh-cn/application-dev/quick-start/module-structure.md @RayShih +zh-cn/application-dev/quick-start/resource-categories-and-access.md @RayShih +zh-cn/application-dev/quick-start/arkts-get-started.md @gaoyong @niejiteng @jumozhanjiang @HelloCrease +zh-cn/application-dev/quick-start/arkts-basic-ui-description.md @gaoyong @niejiteng @jumozhanjiang @HelloCrease +zh-cn/application-dev/quick-start/arkts-state-mgmt-concepts.md @gaoyong @niejiteng @jumozhanjiang @HelloCrease +zh-cn/application-dev/quick-start/arkts-state-mgmt-page-level.md @gaoyong @niejiteng @jumozhanjiang @HelloCrease +zh-cn/application-dev/quick-start/arkts-state-mgmt-application-level.md @gaoyong @niejiteng @jumozhanjiang @HelloCrease +zh-cn/application-dev/quick-start/arkts-dynamic-ui-elememt-building.md @gaoyong @niejiteng @jumozhanjiang @HelloCrease +zh-cn/application-dev/quick-start/arkts-rendering-control.md @gaoyong @niejiteng @jumozhanjiang @HelloCrease +zh-cn/application-dev/quick-start/arkts-restrictions-and-extensions.md @gaoyong @niejiteng @jumozhanjiang @HelloCrease +zh-cn/application-dev/napi/napi-guidelines.md @RayShih @huaweimaxuchu @niulihua @tomatodevboy +zh-cn/application-dev/napi/drawing-guidelines.md @zengyawen @zhangqiang183 @wind_zj @zxg-gitee +zh-cn/application-dev/napi/rawfile-guidelines.md @ningningW @Buda-Liu @budda-wang @yangqing3 +zh-cn/application-dev/reference/js-service-widget-ui/ @HelloCrease zh-cn/application-dev/faqs/ @zengyawen -zh-cn/application-dev/reference/apis/js-apis-useriam-faceauth.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-userfilemanager.md @zengyawen -zh-cn/application-dev/reference/apis/js-apis-cryptoFramework.md @zengyawen -zh-cn/application-dev/reference/apis/Readme-CN.md @zengyawen \ No newline at end of file +zh-cn/application-dev/file-management/ @zengyawen +zh-cn/application-dev/application-test/ @ningningW +zh-cn/application-dev/device-usage-statistics/ @RayShih @shuaytao @wangzhen107 @inter515 + +zh-cn/application-dev/reference/apis/js-apis-ability-context.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-ability-errorCode.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-ability-wantConstant.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-abilityAccessCtrl.md @nianCode @zengyawen @shuqinglin2 @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-abilityDelegatorRegistry.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-abilityrunninginfo.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-abilitystagecontext.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-accessibility-extension-context.md @mupceet @RayShih @mupceet @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-animator.md @huaweimaxuchu @HelloCrease @niulihua @tomatodevboy +zh-cn/application-dev/reference/apis/js-apis-appAccount.md @nianCode @zengyawen @JiDong-CS @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-application-ability.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-abilityConstant.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-abilityDelegator.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-abilityDelegatorArgs.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-abilityLifecycleCallback.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-abilityManager.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-abilityMonitor.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-abilitystage.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-AccessibilityExtensionAbility.md @mupceet @RayShih @mupceet @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-applicationContext.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-context.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-DataShareExtensionAbility.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-application-EnvironmentCallback.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-MissionSnapshot.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-shellCmdResult.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-StartOptions.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-staticSubscriberExtensionAbility.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-Want.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-WindowExtensionAbility.md @zhangqiang183 @ge-yafang @zhouyaoying @zxg-gitee +zh-cn/application-dev/reference/apis/js-apis-appmanager.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-arraylist.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-audio.md @liuyuehua1 @zengyawen @magekkkk @currydavids +zh-cn/application-dev/reference/apis/js-apis-backgroundTaskManager.md @wangwenli_wolf @ningningW @tangtiantian2021 @nan-xiansen +zh-cn/application-dev/reference/apis/js-apis-battery-info.md @aqxyjay @zengyawen @aqxyjay @alien0208 +zh-cn/application-dev/reference/apis/js-apis-bluetooth.md @cheng_guohong @RayShih @cheng_guohong @quanli125 +zh-cn/application-dev/reference/apis/js-apis-brightness.md @aqxyjay @zengyawen @aqxyjay @alien0208 +zh-cn/application-dev/reference/apis/js-apis-buffer.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-bundle-AbilityInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundle-ApplicationInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundle-BundleInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundle-BundleInstaller.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundle-CustomizeData.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-Bundle-distributedBundle.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundle-ElementName.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundle-HapModuleInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-Bundle-InnerBundleManager.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundle-LauncherAbilityInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundle-ModuleInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundle-PermissionDef.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundle-remoteAbilityInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundle-ShortcutInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-Bundle.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bytrace.md @stone2050 @zengyawen @stesen @elsen-liu +zh-cn/application-dev/reference/apis/js-apis-call.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-camera.md @liuyuehua1 @zengyawen @nongwa @currydavids +zh-cn/application-dev/reference/apis/js-apis-cardEmulation.md @cheng_guohong @RayShih @cheng_guohong @quanli125 +zh-cn/application-dev/reference/apis/js-apis-commonEvent.md @jayleehw @RayShih @li-weifeng2 @currydavids +zh-cn/application-dev/reference/apis/js-apis-configuration.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-configurationconstant.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-connectedTag.md @cheng_guohong @RayShih @cheng_guohong @quanli125 +zh-cn/application-dev/reference/apis/js-apis-contact.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-Context.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-continuation-continuationExtraParams.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-continuation-continuationManager.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-continuation-continuationResult.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-convertxml.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-data-ability.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-data-dataShare.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-data-dataSharePredicates.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-data-DataShareResultSet.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-data-distributedobject.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-data-preferences.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-data-rdb.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-data-resultset.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-data-storage.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-data-ValuesBucket.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-dataAbilityHelper.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-DataUriUtils.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-deque.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-device-info.md @mupceet @zengyawen @handyohos @nan-xiansen +zh-cn/application-dev/reference/apis/js-apis-device-manager.md @intermilano @RayShih @william-ligang @liuhonggang123 +zh-cn/application-dev/reference/apis/js-apis-deviceUsageStatistics.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-display.md @zhangqiang183 @ge-yafang @zhouyaoying @zxg-gitee +zh-cn/application-dev/reference/apis/js-apis-distributed-account.md @nianCode @zengyawen @JiDong-CS @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-distributed-data.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-distributedMissionManager.md @wangwenli_wolf @ningningW @tangtiantian2021 @nan-xiansen +zh-cn/application-dev/reference/apis/js-apis-document.md @panqinxu @zengyawen @bubble_mao @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-effectKit.md @zhangqiang183 @ge-yafang @wind_zj @zxg-gitee +zh-cn/application-dev/reference/apis/js-apis-emitter.md @jayleehw @RayShih @li-weifeng2 @currydavids +zh-cn/application-dev/reference/apis/js-apis-EnterpriseAdminExtensionAbility.md @Buda-Liu @ningningW @budda-wang @yangqing3 +zh-cn/application-dev/reference/apis/js-apis-environment.md @panqinxu @zengyawen @bubble_mao @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-errorManager.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-eventhub.md @jayleehw @RayShih @li-weifeng2 @currydavids +zh-cn/application-dev/reference/apis/js-apis-extension-context.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-extensionrunninginfo.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-faultLogger.md @stone2050 @zengyawen @stesen @elsen-liu +zh-cn/application-dev/reference/apis/js-apis-featureAbility.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-fileio.md @panqinxu @zengyawen @bubble_mao @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-formbindingdata.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-formerror.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-formextension.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-formextensioncontext.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-formhost.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-formInfo.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-formprovider.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-geolocation.md @cheng_guohong @RayShih @cheng_guohong @xiangkejin123 +zh-cn/application-dev/reference/apis/js-apis-hashmap.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-hashset.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-hiappevent.md @stone2050 @zengyawen @stesen @elsen-liu +zh-cn/application-dev/reference/apis/js-apis-hichecker.md @stone2050 @zengyawen @stesen @elsen-liu +zh-cn/application-dev/reference/apis/js-apis-hidebug.md @stone2050 @zengyawen @stesen @elsen-liu +zh-cn/application-dev/reference/apis/js-apis-hilog.md @stone2050 @zengyawen @stesen @elsen-liu +zh-cn/application-dev/reference/apis/js-apis-hisysevent.md @stone2050 @zengyawen @stesen @elsen-liu +zh-cn/application-dev/reference/apis/js-apis-hitracechain.md @stone2050 @zengyawen @stesen @elsen-liu +zh-cn/application-dev/reference/apis/js-apis-hitracemeter.md @stone2050 @zengyawen @stesen @elsen-liu +zh-cn/application-dev/reference/apis/js-apis-http.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-huks.md @gaoyong @zengyawen @niejiteng @jumozhanjiang +zh-cn/application-dev/reference/apis/js-apis-i18n.md @Buda-Liu @ningningW @budda-wang @yangqing3 +zh-cn/application-dev/reference/apis/js-apis-image.md @zhangqiang183 @zengyawen @chenyuheng @zxg-gitee +zh-cn/application-dev/reference/apis/js-apis-inputconsumer.md @mayunteng_1 @ningningW @cococoler @alien0208 +zh-cn/application-dev/reference/apis/js-apis-inputdevice.md @mayunteng_1 @ningningW @cococoler @alien0208 +zh-cn/application-dev/reference/apis/js-apis-inputevent.md @mayunteng_1 @ningningW @cococoler @alien0208 +zh-cn/application-dev/reference/apis/js-apis-inputeventclient.md @mayunteng_1 @ningningW @cococoler @alien0208 +zh-cn/application-dev/reference/apis/js-apis-inputmethod-extension-ability.md @feng-aiwen @ningningW @SuperShrimp @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-inputmethod-extension-context.md @feng-aiwen @ningningW @SuperShrimp @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-inputmethod.md @feng-aiwen @ningningW @SuperShrimp @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-inputmethodengine.md @feng-aiwen @ningningW @SuperShrimp @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-inputmonitor.md @mayunteng_1 @ningningW @cococoler @alien0208 +zh-cn/application-dev/reference/apis/js-apis-intl.md @Buda-Liu @ningningW @budda-wang @yangqing3 +zh-cn/application-dev/reference/apis/js-apis-keycode.md @mayunteng_1 @ningningW @cococoler @alien0208 +zh-cn/application-dev/reference/apis/js-apis-keyevent.md @mayunteng_1 @ningningW @cococoler @alien0208 +zh-cn/application-dev/reference/apis/js-apis-lightweightmap.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-lightweightset.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-linkedlist.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-list.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-logs.md @huaweimaxuchu @ningningW @niulihua @tomatodevboy +zh-cn/application-dev/reference/apis/js-apis-media.md @liuyuehua1 @zengyawen @xxb-wzy @currydavids +zh-cn/application-dev/reference/apis/js-apis-medialibrary.md @panqinxu @zengyawen @bubble_mao @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-mediaquery.md @huaweimaxuchu @HelloCrease @niulihua @tomatodevboy +zh-cn/application-dev/reference/apis/js-apis-missionManager.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-mouseevent.md @mayunteng_1 @ningningW @cococoler @alien0208 +zh-cn/application-dev/reference/apis/js-apis-net-connection.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-nfcController.md @cheng_guohong @RayShih @cheng_guohong @quanli125 +zh-cn/application-dev/reference/apis/js-apis-nfcTag.md @cheng_guohong @RayShih @cheng_guohong @quanli125 +zh-cn/application-dev/reference/apis/js-apis-notification.md @jayleehw @RayShih @li-weifeng2 @currydavids +zh-cn/application-dev/reference/apis/js-apis-observer.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-osAccount.md @nianCode @zengyawen @JiDong-CS @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-particleAbility.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-pasteboard.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-permissionrequestresult.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-plainarray.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-pointer.md @mayunteng_1 @ningningW @cococoler @alien0208 +zh-cn/application-dev/reference/apis/js-apis-power.md @aqxyjay @zengyawen @aqxyjay @alien0208 +zh-cn/application-dev/reference/apis/js-apis-privacyManager.md @nianCode @zengyawen @shuqinglin2 @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-process.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-processrunninginfo.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-processrunninginformation.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-prompt.md @huaweimaxuchu @HelloCrease @niulihua @tomatodevboy +zh-cn/application-dev/reference/apis/js-apis-queue.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-radio.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-reminderAgent.md @jayleehw @RayShih @li-weifeng2 @currydavids +zh-cn/application-dev/reference/apis/js-apis-request.md @feng-aiwen @ningningW @nagexiucai @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-resource-manager.md @Buda-Liu @ningningW @budda-wang @yangqing3 +zh-cn/application-dev/reference/apis/js-apis-router.md @huaweimaxuchu @HelloCrease @niulihua @tomatodevboy +zh-cn/application-dev/reference/apis/js-apis-rpc.md @xuepianpian @RayShih @zhaopeng_gitee @vagrant_world +zh-cn/application-dev/reference/apis/js-apis-runninglock.md @aqxyjay @zengyawen @aqxyjay @alien0208 +zh-cn/application-dev/reference/apis/js-apis-screen-lock.md @feng-aiwen @ningningW @wangzhangjun @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-screen.md @zhangqiang183 @ge-yafang @zhouyaoying @zxg-gitee +zh-cn/application-dev/reference/apis/js-apis-screenshot.md @zhangqiang183 @ge-yafang @zhouyaoying @zxg-gitee +zh-cn/application-dev/reference/apis/js-apis-securityLabel.md @panqinxu @zengyawen @bubble_mao @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-sensor.md @hellohyh001 @ningningW @butterls @star-wind-snow-and-rain +zh-cn/application-dev/reference/apis/js-apis-service-extension-ability.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-service-extension-context.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-settings.md @tetex @ge-yafang @cnzhaoxiaohu @anning7 +zh-cn/application-dev/reference/apis/js-apis-sim.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-sms.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-socket.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-stack.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-statfs.md @panqinxu @zengyawen @bubble_mao @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-storage-statistics.md @panqinxu @zengyawen @bubble_mao @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-system-app.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-system-battery.md @aqxyjay @zengyawen @aqxyjay @alien0208 +zh-cn/application-dev/reference/apis/js-apis-system-bluetooth.md @cheng_guohong @RayShih @cheng_guohong @quanli125 +zh-cn/application-dev/reference/apis/js-apis-system-brightness.md @aqxyjay @zengyawen @aqxyjay @alien0208 +zh-cn/application-dev/reference/apis/js-apis-system-cipher.md @gaoyong @zengyawen @niejiteng @jumozhanjiang +zh-cn/application-dev/reference/apis/js-apis-system-configuration.md @Buda-Liu @ningningW @budda-wang @tomatodevboy +zh-cn/application-dev/reference/apis/js-apis-system-device.md @mupceet @zengyawen @handyohos @nan-xiansen +zh-cn/application-dev/reference/apis/js-apis-system-fetch.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-system-file.md @panqinxu @zengyawen @bubble_mao @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-system-location.md @cheng_guohong @RayShih @cheng_guohong @xiangkejin123 +zh-cn/application-dev/reference/apis/js-apis-system-mediaquery.md @huaweimaxuchu @HelloCrease @niulihua @tomatodevboy +zh-cn/application-dev/reference/apis/js-apis-system-network.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-system-notification.md @jayleehw @RayShih @li-weifeng2 @currydavids +zh-cn/application-dev/reference/apis/js-apis-system-package.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-system-parameter.md @mupceet @zengyawen @handyohos @nan-xiansen +zh-cn/application-dev/reference/apis/js-apis-system-prompt.md @huaweimaxuchu @HelloCrease @niulihua @tomatodevboy +zh-cn/application-dev/reference/apis/js-apis-system-request.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-system-router.md @huaweimaxuchu @HelloCrease @niulihua @tomatodevboy +zh-cn/application-dev/reference/apis/js-apis-system-sensor.md @hellohyh001 @ningningW @butterls @star-wind-snow-and-rain +zh-cn/application-dev/reference/apis/js-apis-system-storage.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-system-time.md @feng-aiwen @ningningW @illybyy @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-system-timer.md @feng-aiwen @ningningW @illybyy @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-system-vibrate.md @hellohyh001 @ningningW @butterls @star-wind-snow-and-rain +zh-cn/application-dev/reference/apis/js-apis-telephony-data.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-testRunner.md @inter515 @littlejerry1 @RayShih @inter515 @jiyong +zh-cn/application-dev/reference/apis/js-apis-thermal.md @aqxyjay @zengyawen @aqxyjay @alien0208 +zh-cn/application-dev/reference/apis/js-apis-timer.md @huaweimaxuchu @HelloCrease @niulihua @tomatodevboy +zh-cn/application-dev/reference/apis/js-apis-touchevent.md @mayunteng_1 @ningningW @cococoler @alien0208 +zh-cn/application-dev/reference/apis/js-apis-treemap.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-treeset.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-uitest.md @inter515 @ningningW @inter515 @jiyong +zh-cn/application-dev/reference/apis/js-apis-update.md @hughes802 @ningningW @zhangzhengxue @mamba-ting +zh-cn/application-dev/reference/apis/js-apis-uri.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-url.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-usb.md @jasonyujia @ge-yafang @andeszhang @liuhonggang123 +zh-cn/application-dev/reference/apis/js-apis-useriam-userauth.md @gaoyong @zengyawen @niejiteng @jumozhanjiang +zh-cn/application-dev/reference/apis/js-apis-util.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-vector.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-vibrator.md @hellohyh001 @ningningW @butterls @star-wind-snow-and-rain +zh-cn/application-dev/reference/apis/js-apis-volumemanager.md @panqinxu @zengyawen @bubble_mao @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-wallpaper.md @feng-aiwen @ningningW @wangzhangjun @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-wantAgent.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-webgl.md @zhangqiang183 @ge-yafang @wind_zj @zxg-gitee +zh-cn/application-dev/reference/apis/js-apis-webgl2.md @zhangqiang183 @ge-yafang @wind_zj @zxg-gitee +zh-cn/application-dev/reference/apis/js-apis-webSocket.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-wifi.md @cheng_guohong @RayShih @cheng_guohong @quanli125 +zh-cn/application-dev/reference/apis/js-apis-wifiext.md @cheng_guohong @RayShih @cheng_guohong @quanli125 +zh-cn/application-dev/reference/apis/js-apis-window.md @zhangqiang183 @ge-yafang @zhouyaoying @zxg-gitee +zh-cn/application-dev/reference/apis/js-apis-windowAnimationManager.md @zhangqiang183 @ge-yafang @wind_zj @zxg-gitee +zh-cn/application-dev/reference/apis/js-apis-worker.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-workScheduler.md @wangwenli_wolf @ningningW @tangtiantian2021 @nan-xiansen +zh-cn/application-dev/reference/apis/js-apis-WorkSchedulerExtensionAbility.md @wangwenli_wolf @ningningW @tangtiantian2021 @nan-xiansen +zh-cn/application-dev/reference/apis/js-apis-xml.md @gongjunsong @ge-yafang @flyingwolf @BlackStone +zh-cn/application-dev/reference/apis/js-apis-zlib.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-webview.md @bigpumpkin @HelloCrease @litao33 @zhang-xinyue15 +zh-cn/application-dev/reference/apis/js-apis-ability-ability.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-ability-abilityResult.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-ability-Want.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-accessibility-config.md @mupceet @RayShih @mupceet @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-accessibility-GesturePath.md @mupceet @RayShih @mupceet @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-accessibility-GesturePoint.md @mupceet @RayShih @mupceet @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-accessibility.md @mupceet @RayShih @mupceet @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-app-ability-appRecovery.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-appControl.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-configuration.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-configurationConstant.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-application-quickFixManager.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen +zh-cn/application-dev/reference/apis/js-apis-avsession.md @liuyuehua1 @zengyawen @saga2020 @currydavids +zh-cn/application-dev/reference/apis/js-apis-batteryStatistics.md @aqxyjay @zengyawen @aqxyjay @alien0208 +zh-cn/application-dev/reference/apis/js-apis-Bundle-BundleStatusCallback.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-abilityInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-applicationInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-bundleInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-dispatchInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-elementName.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-extensionAbilityInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-hapModuleInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-launcherAbilityInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-metadata.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-packInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-permissionDef.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-remoteAbilityInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager-shortcutInfo.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleManager.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-bundleMonitor.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-colorSpaceManager.md @zhangqiang183 @ge-yafang @wind_zj @zxg-gitee +zh-cn/application-dev/reference/apis/js-apis-commonEventManager.md @jayleehw @RayShih @li-weifeng2 @currydavids +zh-cn/application-dev/reference/apis/js-apis-configPolicy.md @Buda-Liu @ningningW @budda-wang @yangqing3 +zh-cn/application-dev/reference/apis/js-apis-cooperate.md @mayunteng_1 @ningningW @cococoler @alien0208 +zh-cn/application-dev/reference/apis/js-apis-cryptoFramework.md @gaoyong @zengyawen @niejiteng @jumozhanjiang +zh-cn/application-dev/reference/apis/js-apis-curve.md @huaweimaxuchu @HelloCrease @niulihua @tomatodevboy +zh-cn/application-dev/reference/apis/js-apis-defaultAppManager.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-distributedBundle.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-distributedKVStore.md @feng-aiwen @ge-yafang @gong-a-shi @logic42 +zh-cn/application-dev/reference/apis/js-apis-enterprise-adminManager.md @Buda-Liu @ningningW @budda-wang @yangqing3 +zh-cn/application-dev/reference/apis/js-apis-enterprise-dateTimeManager.md @Buda-Liu @ningningW @budda-wang @yangqing3 +zh-cn/application-dev/reference/apis/js-apis-fileAccess.md @panqinxu @zengyawen @bubble_mao @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-fileExtensionInfo.md @panqinxu @zengyawen @bubble_mao @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-freeInstall.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-geoLocationManager.md @cheng_guohong @RayShih @cheng_guohong @xiangkejin123 +zh-cn/application-dev/reference/apis/js-apis-hiviewdfx-hiappevent.md @stone2050 @zengyawen @stesen @elsen-liu +zh-cn/application-dev/reference/apis/js-apis-inputmethod-subtype.md @feng-aiwen @ningningW @SuperShrimp @murphy1984 +zh-cn/application-dev/reference/apis/js-apis-installer.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-launcherBundleManager.md @shuaytao @RayShih @wangzhen107 @inter515 +zh-cn/application-dev/reference/apis/js-apis-matrix4.md @huaweimaxuchu @HelloCrease @niulihua @tomatodevboy +zh-cn/application-dev/reference/apis/js-apis-net-ethernet.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-net-sharing.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785 +zh-cn/application-dev/reference/apis/js-apis-nfctech.md @cheng_guohong @RayShih @cheng_guohong @quanli125 +zh-cn/application-dev/reference/apis/js-apis-promptAction.md @cheng_guohong @RayShih @cheng_guohong @quanli125 +zh-cn/application-dev/reference/apis/js-apis-reminderAgentManager.md @wangwenli_wolf @ningningW @tangtiantian2021 @nan-xiansen +zh-cn/application-dev/reference/apis/js-apis-resourceschedule-backgroundTaskManager.md @wangwenli_wolf @ningningW @tangtiantian2021 @nan-xiansen +zh-cn/application-dev/reference/apis/js-apis-resourceschedule-deviceUsageStatistics.md @wangwenli_wolf @ningningW @tangtiantian2021 @nan-xiansen +zh-cn/application-dev/reference/apis/js-apis-resourceschedule-workScheduler.md @wangwenli_wolf @ningningW @tangtiantian2021 @nan-xiansen +zh-cn/application-dev/reference/apis/js-apis-stationary.md @mayunteng_1 @ningningW @cococoler @alien0208 +zh-cn/application-dev/reference/apis/js-apis-system-capability.md taiyipei taiyipei BlackStone +zh-cn/application-dev/reference/apis/js-apis-system-parameterV9.md @mupceet @zengyawen @handyohos @nan-xiansen +zh-cn/application-dev/reference/apis/js-apis-tagSession.md @cheng_guohong @RayShih @cheng_guohong @quanli125 +zh-cn/application-dev/reference/apis/js-apis-usb-deprecated.md @cheng_guohong @RayShih @cheng_guohong @quanli125 +zh-cn/application-dev/reference/apis/js-apis-userFileManager.md @panqinxu @zengyawen @bubble_mao @jinhaihw +zh-cn/application-dev/reference/apis/js-apis-useriam-faceauth.md @gaoyong @zengyawen @niejiteng @jumozhanjiang + +zh-cn/application-dev/reference/errorcodes/errorcode-ability.md @RayShih +zh-cn/application-dev/reference/errorcodes/errorcode-access-token.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-accessibility.md @RayShih +zh-cn/application-dev/reference/errorcodes/errorcode-account.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-animator.md @HelloCrease +zh-cn/application-dev/reference/errorcodes/errorcode-app-account.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-audio.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-avsession.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-backgroundTaskMgr.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-batteryStatistics.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-brightness.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-buffer.md @ge-yafang +zh-cn/application-dev/reference/errorcodes/errorcode-bundle.md @RayShih +zh-cn/application-dev/reference/errorcodes/errorcode-colorspace-manager.md @ge-yafang +zh-cn/application-dev/reference/errorcodes/errorcode-CommonEventService.md @RayShih +zh-cn/application-dev/reference/errorcodes/errorcode-containers.md @ge-yafang +zh-cn/application-dev/reference/errorcodes/errorcode-data-rdb.md @ge-yafang +zh-cn/application-dev/reference/errorcodes/errorcode-datashare.md @ge-yafang +zh-cn/application-dev/reference/errorcodes/errorcode-device-manager.md @RayShih +zh-cn/application-dev/reference/errorcodes/errorcode-DeviceUsageStatistics.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-display.md @ge-yafang +zh-cn/application-dev/reference/errorcodes/errorcode-distributed-dataObject.md @ge-yafang +zh-cn/application-dev/reference/errorcodes/errorcode-distributedKVStore.md @ge-yafang +zh-cn/application-dev/reference/errorcodes/errorcode-DistributedNotificationService.md @RayShih +zh-cn/application-dev/reference/errorcodes/errorcode-DistributedSchedule.md @RayShih +zh-cn/application-dev/reference/errorcodes/errorcode-enterpriseDeviceManager.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-faultlogger.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-filemanagement.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-geoLocationManager.md @RayShih +zh-cn/application-dev/reference/errorcodes/errorcode-hiappevent.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-hisysevent.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-hiviewdfx-hidebug.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-huks.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-i18n.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-inputmethod-framework.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-multimodalinput.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-nfc.md @RayShih +zh-cn/application-dev/reference/errorcodes/errorcode-pasteboard.md @ge-yafang +zh-cn/application-dev/reference/errorcodes/errorcode-power.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-preferences.md @ge-yafang +zh-cn/application-dev/reference/errorcodes/errorcode-promptAction.md @HelloCrease +zh-cn/application-dev/reference/errorcodes/errorcode-reminderAgentManager.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-request.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-resource-manager.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-router.md @HelloCrease +zh-cn/application-dev/reference/errorcodes/errorcode-rpc.md @RayShih +zh-cn/application-dev/reference/errorcodes/errorcode-runninglock.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-sensor.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-system-parameterV9.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-thermal.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-uitest.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-universal.md @RayShih +zh-cn/application-dev/reference/errorcodes/errorcode-update.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-usb.md @ge-yafang +zh-cn/application-dev/reference/errorcodes/errorcode-useriam.md @zengyawen +zh-cn/application-dev/reference/errorcodes/errorcode-vibrator.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-webview.md @HelloCrease +zh-cn/application-dev/reference/errorcodes/errorcode-window.md @ge-yafang +zh-cn/application-dev/reference/errorcodes/errorcode-workScheduler.md @ningningW +zh-cn/application-dev/reference/errorcodes/errorcode-zlib.md @RayShih diff --git a/README.md b/README.md index 0b1fe4ea284ed5df055c0031d96d3cfb759948a3..602a868e0c5966d52b77eff891a6f32232c7d579 100644 --- a/README.md +++ b/README.md @@ -18,15 +18,15 @@ This repository stores device and application development documents provided by - master: the latest version. - - OpenHarmony 3.2 Beta1. [Learn more](en/release-notes/OpenHarmony-v3.2-beta1.md) + - OpenHarmony 3.2 Beta3. [Learn more](en/release-notes/OpenHarmony-v3.2-beta3.md) - OpenHarmony 3.1 Release. [Learn more](en/release-notes/OpenHarmony-v3.1-release.md) - This version is upgraded to OpenHarmony 3.1.1 LTS. [Learn more](en/release-notes/OpenHarmony-v3.1.1-release.md) + This version is upgraded to OpenHarmony 3.1.3 Release. [Learn more](en/release-notes/OpenHarmony-v3.1.3-release.md) - OpenHarmony 3.0 LTS. [Learn more](en/release-notes/OpenHarmony-v3.0-LTS.md) - This version is upgraded to OpenHarmony 3.0.5 LTS. [Learn more](en/release-notes/OpenHarmony-v3.0.5-LTS.md) + This version is upgraded to OpenHarmony 3.0.6 LTS. [Learn more](en/release-notes/OpenHarmony-v3.0.6-LTS.md) - OpenHarmony 2.2 Beta2. [Learn more](en/release-notes/OpenHarmony-v2.2-beta2.md) @@ -34,14 +34,14 @@ This repository stores device and application development documents provided by ### Historical Stable Versions -OpenHarmony_v1.x_release: OpenHarmony v1.1.4 LTS. [Learn more](en/release-notes/OpenHarmony-v1-1-4-LTS.md) +OpenHarmony_v1.x_release: OpenHarmony v1.1.5 LTS. [Learn more](en/release-notes/OpenHarmony-v1.1.5-LTS.md) [More versions](en/release-notes/) ## Third-Party Open-Source Software and License Notice -Third-party license: [Third-Party Open-Source Software and License Notice](en/contribute/third-party-open-source-software-and-license-notice.md) +Third-party license: [Third-Party Open-Source Software and License Notice](en/contribute/open-source-software-and-license-notice.md) ## Contribution diff --git a/README_zh.md b/README_zh.md index ebf1bc8d7557d35f99eaacf8fd1427972d61d3b0..386fa1d7449553f92f399839d947a0dacd4e18b8 100644 --- a/README_zh.md +++ b/README_zh.md @@ -18,15 +18,15 @@ - master:最新开发版本。 - - OpenHarmony 3.2 Beta2版本:点击[此处](zh-cn/release-notes/OpenHarmony-v3.2-beta2.md)了解版本详情。 + - OpenHarmony 3.2 Beta3版本:点击[此处](zh-cn/release-notes/OpenHarmony-v3.2-beta3.md)了解版本详情。 - OpenHarmony 3.1 Release版本:点击[此处](zh-cn/release-notes/OpenHarmony-v3.1-release.md)了解版本详情。 - 该已更新至OpenHarmony 3.1.1 Release,点击[此处](zh-cn/release-notes/OpenHarmony-v3.1.1-release.md)了解版本详情。 + 该版本已更新至OpenHarmony 3.1.3 Release,点击[此处](zh-cn/release-notes/OpenHarmony-v3.1.3-release.md)了解版本详情。 - OpenHarmony 3.0 LTS版本:点击[此处](zh-cn/release-notes/OpenHarmony-v3.0-LTS.md)了解版本详情。 - 该版本已更新至OpenHarmony 3.0.5 LTS,点击[此处](zh-cn/release-notes/OpenHarmony-v3.0.5-LTS.md)了解版本详情。 + 该版本已更新至OpenHarmony 3.0.6 LTS,点击[此处](zh-cn/release-notes/OpenHarmony-v3.0.6-LTS.md)了解版本详情。 - OpenHarmony 2.2 Beta2版本:点击[此处](zh-cn/release-notes/OpenHarmony-v2.2-beta2.md)了解版本详情。 @@ -34,7 +34,7 @@ ### 历史稳定版本 -OpenHarmony_v1.x_release:OpenHarmony 1.1.4 LTS稳定版本,点击[此处](zh-cn/release-notes/OpenHarmony-v1-1-4-LTS.md)了解版本详情。 +OpenHarmony_v1.x_release:OpenHarmony 1.1.5 LTS稳定版本,点击[此处](zh-cn/release-notes/OpenHarmony-v1.1.5-LTS.md)了解版本详情。 如需了解更多版本详情,点击[此处](zh-cn/release-notes/)。 diff --git a/en/Legal-Notices.md b/en/Legal-Notices.md new file mode 100644 index 0000000000000000000000000000000000000000..80d301770e502de109fbcf861fe456168cd23ab1 --- /dev/null +++ b/en/Legal-Notices.md @@ -0,0 +1,21 @@ +# Legal Notices + +**Copyright (c) 2020-2022 OpenAtom OpenHarmony. All rights reserved.** + +## Copyright + +All copyrights of the OpenHarmony documents are reserved by OpenAtom OpenHarmony. + +The OpenHarmony documents are licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). For easier understanding, you can visit [Creative Commons](https://creativecommons.org/licenses/by/4.0/) to get a human-readable summary of the license. For the complete content, see [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/legalcode). + +## Trademarks and Permissions + +No content provided in the OpenHarmony documentation shall be deemed as a grant of the approval or right to use any trademark, name, or logo of the OpenAtom Foundation and OpenAtom OpenHarmony. No third parties shall use any of the aforementioned trademarks, names, or logos in any way without explicit prior written permission of the OpenAtom Foundation. + +## Disclaimer + +The information in the OpenHarmony documents is subject to change without notice. + +The OpenHarmony documents are provided without any express or implied warranty. In any case, the OpenAtom Foundation or the copyright owner is not liable for any direct or indirect loss arising from the use of the OpenHarmony documents, regardless of the cause or legal theory, even if the OpenHarmony documents have stated that there is a possibility of such loss. + + \ No newline at end of file diff --git a/en/OpenHarmony-Overview.md b/en/OpenHarmony-Overview.md index 1331ac52206cf1980ce59a7def62bfd32c27e406..5fbc55f9a12d9c774f7a7295d68cb7b2659852cd 100644 --- a/en/OpenHarmony-Overview.md +++ b/en/OpenHarmony-Overview.md @@ -146,21 +146,19 @@ The following table describes the subsystems of OpenHarmony. For details about t ## Supported Development Boards -Currently, the OpenHarmony community supports 17 types of development boards, which are listed in [Development Boards Supported](device-dev/dev-board-on-the-master.md). The following table describes three of them, which are the first three integrated into the OpenHarmony master. You can visit http://ci.openharmony.cn/dailys/dailybuilds to obtain daily builds. +Currently, the OpenHarmony community supports 22 types of development boards, which are listed in [Development Boards Supported](device-dev/dev-board-on-the-master.md). The following table describes three of them, which are the first three integrated into the OpenHarmony master. You can visit http://ci.openharmony.cn/dailys/dailybuilds to obtain daily builds. | System Type| Board Model| Chip Model|
Function Description and Use Case
| Application Scenario| Code Repository | | -------- | -------- | -------- | -------- | -------- | -------- | -| Standard system| Runhe HH-SCDAYU200| RK3568 |
Function description:
Bolstered by the Rockchip RK3568, the HH-SCDAYU200 development board integrates the dual-core GPU and efficient NPU. Its quad-core 64-bit Cortex-A55 processor uses the advanced 22 nm fabrication process and is clocked at up to 2.0 GHz. The board is packed with Bluetooth, Wi-Fi, audio, video, and camera features, with a wide range of expansion ports to accommodate various video input and outputs. It comes with dual GE auto-sensing RJ45 ports, so it can be used in multi-connectivity products, such as network video recorders (NVRs) and industrial gateways.
Use case:
[DAYU200 Use Case](device-dev/porting/porting-dayu200-on_standard-demo.md)
| Entertainment, easy travel, and smart home, such as kitchen hoods, ovens, and treadmills.| [device_soc_rockchip](https://gitee.com/openharmony/device_soc_rockchip)
[device_board_hihope](https://gitee.com/openharmony/device_board_hihope)
[vendor_hihope](https://gitee.com/openharmony/vendor_hihope)
| +| Standard system| Runhe HH-SCDAYU200| RK3568 |
Function description:
Bolstered by the Rockchip RK3568, the HH-SCDAYU200 development board integrates the dual-core GPU and efficient NPU. Its quad-core 64-bit Cortex-A55 processor uses the advanced 22 nm fabrication process and is clocked at up to 2.0 GHz. The board is packed with Bluetooth, Wi-Fi, audio, video, and camera features, with a wide range of expansion ports to accommodate various video input and outputs. It comes with dual GE auto-sensing RJ45 ports, so it can be used in multi-connectivity products, such as network video recorders (NVRs) and industrial gateways.
| Entertainment, easy travel, and smart home, such as kitchen hoods, ovens, and treadmills.| [device_soc_rockchip](https://gitee.com/openharmony/device_soc_rockchip)
[device_board_hihope](https://gitee.com/openharmony/device_board_hihope)
[vendor_hihope](https://gitee.com/openharmony/vendor_hihope)
| | Small system| Hispark_Taurus | Hi3516DV300 |
Function Description:
Hi3516D V300 is the next-generation system on chip (SoC) for smart HD IP cameras. It integrates the next-generation image signal processor (ISP), H.265 video compression encoder, and high-performance NNIE engine, and delivers high performance in terms of low bit rate, high image quality, intelligent processing and analysis, and low power consumption.
| Smart device with screens, such as refrigerators with screens and head units.| [device_soc_hisilicon](https://gitee.com/openharmony/device_soc_hisilicon)
[device_board_hisilicon](https://gitee.com/openharmony/device_board_hisilicon)
[vendor_hisilicon](https://gitee.com/openharmony/vendor_hisilicon)
| | Mini system| Multi-modal V200Z-R | BES2600 |
Function description:
The multi-modal V200Z-R development board is a high-performance, multi-functional, and cost-effective AIoT SoC powered by the BES2600WM chip of Bestechnic. It integrates a quad-core ARM processor with a frequency of up to 1 GHz as well as dual-mode Wi-Fi and dual-mode Bluetooth. The board supports the 802.11 a/b/g/n/ and BT/BLE 5.2 standards. It is able to accommodate RAM of up to 42 MB and flash memory of up to 32 MB, and supports the MIPI display serial interface (DSI) and camera serial interface (CSI). It is applicable to various AIoT multi-modal VUI and GUI interaction scenarios.
Use case:
[Multi-modal V200Z-R Use Case](device-dev/porting/porting-bes2600w-on-minisystem-display-demo.md)
| Smart hardware, and smart devices with screens, such as speakers and watches.| [device_soc_bestechnic](https://gitee.com/openharmony/device_soc_bestechnic)
[device_board_fnlink](https://gitee.com/openharmony/device_board_fnlink)
[vendor_bestechnic](https://gitee.com/openharmony/vendor_bestechnic)
| ## Getting Started -- [Getting Started for Device Development](device-dev/quick-start/quickstart-ide-lite-overview.md) +- [Getting Started for Device Development](device-dev/quick-start/quickstart-overview.md) - [Getting Started for Application Development](application-dev/quick-start/start-overview.md) - - ## Code Repository Addresses OpenHarmony project: [https://gitee.com/openharmony](https://gitee.com/openharmony) @@ -173,6 +171,8 @@ OpenHarmony archived projects: [https://gitee.com/openharmony-retired](https://g ## OpenHarmony Documentation +[Official website](https://www.openharmony.cn/) + [Chinese version](https://gitee.com/openharmony/docs/tree/master/zh-cn) [English version](https://gitee.com/openharmony/docs/tree/master/en) @@ -197,7 +197,7 @@ For details about how to contribute, see [How to contribute](contribute/how-to-c OpenHarmony complies with Apache License Version 2.0. For details, see the LICENSE in each repository. -OpenHarmony uses third-party open-source software and licenses. For details, see [Third-Party Open-Source Software](https://gitee.com/openharmony/docs/blob/master/en/contribute/third-party-open-source-software-and-license-notice.md). +OpenHarmony uses third-party open-source software and licenses. For details, see [Open Source Software and License Notice](https://gitee.com/openharmony/docs/blob/master/en/contribute/open-source-software-and-license-notice.md). ## Contact Info diff --git a/en/application-dev/IDL/figures/SDKpath.png b/en/application-dev/IDL/figures/SDKpath.png new file mode 100644 index 0000000000000000000000000000000000000000..aa7e33f0246e07fa9f6b8aeb0677c7159dfceb3d Binary files /dev/null and b/en/application-dev/IDL/figures/SDKpath.png differ diff --git a/en/application-dev/IDL/figures/SDKpath2.png b/en/application-dev/IDL/figures/SDKpath2.png new file mode 100644 index 0000000000000000000000000000000000000000..51ac48d2f04d876a204493415b79a5f12e183685 Binary files /dev/null and b/en/application-dev/IDL/figures/SDKpath2.png differ diff --git a/en/application-dev/IDL/idl-guidelines.md b/en/application-dev/IDL/idl-guidelines.md index 661b2532c49d36c79855c3e0530326ef590c7cd2..f165215bad4d663b794c249f8029d33aeeda5863 100644 --- a/en/application-dev/IDL/idl-guidelines.md +++ b/en/application-dev/IDL/idl-guidelines.md @@ -7,7 +7,7 @@ To ensure successful communications between the client and server, interfaces re ![IDL-interface-description](./figures/IDL-interface-description.png) -IDL provides the following functions: +**IDL provides the following functions:** - Declares interfaces provided by system services for external systems, and based on the interface declaration, generates C, C++, JS, or TS code for inter-process communication (IPC) or remote procedure call (RPC) proxies and stubs during compilation. @@ -17,7 +17,7 @@ IDL provides the following functions: ![IPC-RPC-communication-model](./figures/IPC-RPC-communication-model.png) -IDL has the following advantages: +**IDL has the following advantages:** - Services are defined in the form of interfaces in IDL. Therefore, you do not need to focus on implementation details. @@ -149,198 +149,53 @@ The value of <*formal_param_attr*> can be **in**, **out**, or **inout**, indicat ## How to Develop -### Development Using C++ +### Obtaining IDL +On DevEco Studio, choose **Tools > SDK Manager** to view the local installation path of the OpenHarmony SDK. The following figure uses DevEco Studio 3.0.0.993 as an example. +![SDKpath](./figures/SDKpath.png) +![SDKpath](./figures/SDKpath2.png) -#### Creating an IDL File - - You can use C++ to create IDL files. An example IDL file is as follows: +Go to the local installation path, choose **toolchains > 3.x.x.x** (the folder named after the version number), and check whether the executable file of IDL exists. -```cpp - interface OHOS.IIdlTestService { - int TestIntTransaction([in] int data); - void TestStringTransaction([in] String data); - } -``` +> **NOTE**: Use the SDK of the latest version. The use of an earlier version may cause errors in some statements. -You can run the **./idl -gen-cpp -d dir -c dir/iTest.idl** command (**-d** indicates the output directory) to generate the interface file, stub file, and proxy file in the **dir** directory in the execution environment. The names of the generated interface class files are the same as that of the IDL file, except that the file name extensions are **.h** and **.cpp**. For example, the files generated for **IIdlTestService.idl** are **i_idl_test_service.h**, **idl_test_service_proxy.h**, **idl_test_service_stub.h**, **idl_test_service_proxy.cpp**, and **idl_test_service_stub.cpp**. +If the executable file does not exist, download the SDK package from the mirror as instructed in the [Release Notes](../../release-notes). The following uses the [3.2 Beta3](../../release-notes/OpenHarmony-v3.2-beta3.md#acquiring-source-code-from-mirrors) as an example. -#### Exposing Interfaces on the Server +For details about how to replace the SDK package, see [Guide to Switching to Full SDK](../quick-start/full-sdk-switch-guide.md). -The stub class generated by IDL is an abstract implementation of the interface class and declares all methods in the IDL file. +After obtaining the executable file, perform subsequent development steps based on your scenario. -```cpp -#ifndef OHOS_IDLTESTSERVICESTUB_H -#define OHOS_IDLTESTSERVICESTUB_H -#include -#include "iidl_test_service.h" - -namespace OHOS { -class IdlTestServiceStub : public IRemoteStub { -public: - int OnRemoteRequest( - /* [in] */ uint32_t code, - /* [in] */ MessageParcel& data, - /* [out] */ MessageParcel& reply, - /* [in] */ MessageOption& option) override; - -private: - static constexpr int COMMAND_TEST_INT_TRANSACTION = MIN_TRANSACTION_ID + 0; - static constexpr int COMMAND_TEST_STRING_TRANSACTION = MIN_TRANSACTION_ID + 1; -}; -} // namespace OHOS -#endif // OHOS_IDLTESTSERVICESTUB_H -``` +### Development Using TS -You need to inherit the interface class defined in the IDL file and implement the methods in the class. In addition, you need to register the defined services with SAMGR during service initialization. In the following code snippet, **TestService** inherits the **IdlTestServiceStub** interface class and implements the **TestIntTransaction** and **TestStringTransaction** methods. +#### Creating an IDL File -```cpp -#ifndef OHOS_IPC_TEST_SERVICE_H -#define OHOS_IPC_TEST_SERVICE_H - -#include "hilog/log.h" -#include "log_tags.h" -#include "idl_test_service_stub.h" - -namespace OHOS { -class TestService : public IdlTestServiceStub { -public: - TestService(); - ~TestService(); - static int Instantiate(); - ErrCode TestIntTransaction(int data, int &rep) override; - ErrCode TestStringTransaction(const std::string& data) override; -private: - static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "TestService" }; -}; -} // namespace OHOS -#endif // OHOS_IPC_TEST_SERVICE_H -``` +You can use TS to create IDL files. -The sample code for registering a service is as follows: + For example, create a file named **IIdlTestService.idl** with the following content: ```cpp -#include "test_service.h" - -#include - -#include "if_system_ability_manager.h" -#include "ipc_debug.h" -#include "ipc_skeleton.h" -#include "iservice_registry.h" -#include "system_ability_definition.h" - -namespace OHOS { -using namespace OHOS::HiviewDFX; - -int TestService::Instantiate() -{ - ZLOGI(LABEL, "%{public}s call in", __func__); - auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); - if (saMgr == nullptr) { - ZLOGE(LABEL, "%{public}s:fail to get Registry", __func__); - return -ENODEV; - } - - sptr newInstance = new TestService(); - int result = saMgr->AddSystemAbility(IPC_TEST_SERVICE, newInstance); - ZLOGI(LABEL, "%{public}s: IPC_TEST_SERVICE result = %{public}d", __func__, result); - return result; -} - -TestService::TestService() -{ -} - -TestService::~TestService() -{ -} - -ErrCode TestService::TestIntTransaction(int data, int &rep) -{ - ZLOGE(LABEL, " TestService:read from client data = %{public}d", data); - rep = data + data; - return ERR_NONE; -} - -ErrCode TestService::TestStringTransaction(const std::string &data) -{ - ZLOGE(LABEL, "TestService:read string from client data = %{public}s", data.c_str()); - return data.size(); -} -} // namespace OHOS + interface OHOS.IIdlTestService { + int TestIntTransaction([in] int data); + void TestStringTransaction([in] String data); + } ``` -#### Calling Methods from the Client for IPC - -The C++ client obtains the service proxy defined in the system through SAMGR and then invokes the interface provided by the proxy. The sample code is as follows: +Run the **idl -gen-ts -d *dir* -c dir/IIdlTestService.idl** command in the folder where the executable file is located. -```cpp -#include "test_client.h" - -#include "if_system_ability_manager.h" -#include "ipc_debug.h" -#include "ipc_skeleton.h" -#include "iservice_registry.h" -#include "system_ability_definition.h" - -namespace OHOS { -int TestClient::ConnectService() -{ - auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); - if (saMgr == nullptr) { - ZLOGE(LABEL, "get registry fail"); - return -1; - } +-*dir* next to **d** is the target output folder. For example, if the target output folder is **IIdlTestServiceTs**, run the **idl -gen-ts -d IIdlTestServiceTs -c IIdlTestServiceTs/IIdlTestService.idl** command in the folder where the executable file is located. The interface file, stub file, and proxy file are generated in the *dir* directory (**IIdlTestServiceTs** directory in this example) in the execution environment. - sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); - if (object != nullptr) { - ZLOGE(LABEL, "Got test Service object"); - testService_ = (new (std::nothrow) IdlTestServiceProxy(object)); - } +> **NOTE**: The generated interface class file name must be the same as that of the .idl file. Otherwise, an error occurs during code generation. - if (testService_ == nullptr) { - ZLOGE(LABEL, "Could not find Test Service!"); - return -1; - } - - return 0; -} +For example, for an .idl file named **IIdlTestService.idl** and target output directory named **IIdlTestServiceTs**, the directory structure is similar to the following: -void TestClient::StartIntTransaction() -{ - if (testService_ != nullptr) { - ZLOGE(LABEL, "StartIntTransaction"); - [[maybe_unused]] int result = 0; - testService_->TestIntTransaction(1234, result); // 1234 : test number - ZLOGE(LABEL, "Rec result from server %{public}d.", result); - } -} - -void TestClient::StartStringTransaction() -{ - if (testService_ != nullptr) { - ZLOGI(LABEL, "StartIntTransaction"); - testService_->TestStringTransaction("IDL Test"); - } -} -} // namespace OHOS ``` - -### Development Using TS - -#### Creating an IDL File - - You can use TS to create IDL files. An example IDL file is as follows: - -```ts - interface OHOS.IIdlTestService { - int TestIntTransaction([in] int data); - void TestStringTransaction([in] String data); - } +├── IIdlTestServiceTs # IDL code output folder +│ ├── i_idl_test_service.ts # File generated +│ ├── idl_test_service_proxy.ts # File generated +│ ├── idl_test_service_stub.ts # File generated +│ └── IIdlTestService.idl # Constructed .idl file +└── idl.exe # Executable file of IDL ``` -Run the **./idl -c IIdlTestService.idl -gen-ts -d /data/ts/** command (**-d** indicates the output directory) to generate the interface file, stub file, and proxy file in the **/data/ts** directory in the execution environment. The names of the generated interface class files are the same as that of the IDL file, except that the file name extension is **.ts**. For example, the files generated for the **IIdlTestService.idl** file are **i_idl_test_service.ts**, **idl_test_service_proxy.ts**, and **idl_test_service_stub.ts**. - #### Exposing Interfaces on the Server The stub class generated by IDL is an abstract implementation of the interface class and declares all methods in the IDL file. @@ -356,8 +211,8 @@ export default class IdlTestServiceStub extends rpc.RemoteObject implements IIdl super(des); } - onRemoteRequest(code: number, data, reply, option): boolean { - console.log("onRemoteRequest called, code = " + code); + async onRemoteRequestEx(code: number, data, reply, option): Promise { + console.log("onRemoteRequestEx called, code = " + code); switch(code) { case IdlTestServiceStub.COMMAND_TEST_INT_TRANSACTION: { let _data = data.readInt(); @@ -433,7 +288,7 @@ export default { console.log('ServiceAbility want:' + JSON.stringify(want)); console.log('ServiceAbility want name:' + want.bundleName) } catch(err) { - console.log("ServiceAbility error:" + err) + console.log('ServiceAbility error:' + err) } console.info('ServiceAbility onConnect end'); return new IdlTestImp('connect'); @@ -455,13 +310,13 @@ import featureAbility from '@ohos.ability.featureAbility'; function callbackTestIntTransaction(result: number, ret: number): void { if (result == 0 && ret == 124) { - console.log("case 1 success "); + console.log('case 1 success'); } } function callbackTestStringTransaction(result: number): void { if (result == 0) { - console.log("case 2 success "); + console.log('case 2 success'); } } @@ -472,17 +327,17 @@ var onAbilityConnectDone = { testProxy.testStringTransaction('hello', callbackTestStringTransaction); }, onDisconnect:function (elementName) { - console.log("onDisconnectService onDisconnect"); + console.log('onDisconnectService onDisconnect'); }, onFailed:function (code) { - console.log("onDisconnectService onFailed"); + console.log('onDisconnectService onFailed'); } }; function connectAbility: void { let want = { - "bundleName":"com.example.myapplicationidl", - "abilityName": "com.example.myapplicationidl.ServiceAbility" + bundleName: 'com.example.myapplicationidl', + abilityName: 'com.example.myapplicationidl.ServiceAbility' }; let connectionId = -1; connectionId = featureAbility.connectAbility(want, onAbilityConnectDone); @@ -495,7 +350,7 @@ function connectAbility: void { You can send a class from one process to another through IPC interfaces. However, you must ensure that the peer can use the code of this class and this class supports the **marshalling** and **unmarshalling** methods. OpenHarmony uses **marshalling** and **unmarshalling** to serialize and deserialize objects into objects that can be identified by each process. -To create a class that supports the sequenceable type, perform the following operations: +**To create a class that supports the sequenceable type, perform the following operations:** 1. Implement the **marshalling** method, which obtains the current state of the object and serializes the object into a **Parcel** object. 2. Implement the **unmarshalling** method, which deserializes the object from a **Parcel** object. @@ -529,137 +384,3 @@ export default class MySequenceable { private str; } ``` - -## How to Develop for Interworking Between C++ and TS - -### TS Proxy and C++ Stub Development - -#### C++ Service Object - -1. Use C++ to construct an IDL file and run commands to generate interfaces, stub files, and proxy files. - -2. Create a service object, inherit the interface class defined in the C++ stub file, and implement the methods in the class. An example is as follows: - - ```cpp - class IdlTestServiceImpl : public IdlTestServiceStub { - public: - IdlTestServiceImpl() = default; - virtual ~IdlTestServiceImpl() = default; - - ErrCode TestIntTransaction(int _data, int& result) override - { - result = 256; - return ERR_OK; - } - - ErrCode TestStringTransaction(const std::string& _data) override - { - return ERR_OK; - } - }; - ``` - -#### Native APIs in C++ - -C++ provides C++ service objects to TS in the format of native APIs. For example, C++ provides a **GetNativeObject** method, which is used to create an **IdlTestServiceImpl** instance. Using the **NAPI_ohos_rpc_CreateJsRemoteObject** method, you can create a JS remote object for the TS application. - -```cpp -NativeValue* GetNativeObject(NativeEngine& engine, NativeCallbackInfo& info) -{ - sptr impl = new IdlTestServiceImpl(); - napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(reinterpret_cast(&engine), impl); - NativeValue* nativeRemoteObject = reinterpret_cast(napiRemoteObject); - return nativeRemoteObject; -} -``` - -#### TS Proxy Object - -Use TS to construct an IDL file and run commands to generate interfaces, stub files, and proxy files. An example proxy file is as follows: - -```ts -import {testIntTransactionCallback} from "./i_idl_test_service"; -import {testStringTransactionCallback} from "./i_idl_test_service"; -import IIdlTestService from "./i_idl_test_service"; -import rpc from "@ohos.rpc"; - -export default class IdlTestServiceProxy implements IIdlTestService { - constructor(proxy) { - this.proxy = proxy; - } - - testIntTransaction(data: number, callback: testIntTransactionCallback): void - { - let _option = new rpc.MessageOption(); - let _data = new rpc.MessageParcel(); - let _reply = new rpc.MessageParcel(); - _data.writeInt(data); - this.proxy.sendRequest(IdlTestServiceProxy.COMMAND_TEST_INT_TRANSACTION, _data, _reply, _option).then(function(result) { - if (result.errCode === 0) { - let _errCode = result.reply.readInt(); - if (_errCode != 0) { - let _returnValue = undefined; - callback(_errCode, _returnValue); - return; - } - let _returnValue = result.reply.readInt(); - callback(_errCode, _returnValue); - } else { - console.log("sendRequest failed, errCode: " + result.errCode); - } - }) - } - - testStringTransaction(data: string, callback: testStringTransactionCallback): void - { - let _option = new rpc.MessageOption(); - let _data = new rpc.MessageParcel(); - let _reply = new rpc.MessageParcel(); - _data.writeString(data); - this.proxy.sendRequest(IdlTestServiceProxy.COMMAND_TEST_STRING_TRANSACTION, _data, _reply, _option).then(function(result) { - if (result.errCode === 0) { - let _errCode = result.reply.readInt(); - callback(_errCode); - } else { - console.log("sendRequest failed, errCode: " + result.errCode); - } - }) - } - - static readonly COMMAND_TEST_INT_TRANSACTION = 1; - static readonly COMMAND_TEST_STRING_TRANSACTION = 2; - private proxy -} -``` - -#### Interworking Between TS and C++ Applications - -1. The TS application invokes the native API to obtain the remote C++ service object. -2. Construct a TS proxy and transfers the remote C++ service object to it. -3. Use the TS proxy to call the method declared in the IDL file to implement the interworking between the TS proxy and C++ stub. The following is an example: - -```ts -import IdlTestServiceProxy from './idl_test_service_proxy' -import nativeMgr from 'nativeManager'; - -function testIntTransactionCallback(errCode: number, returnValue: number) -{ - console.log("errCode: " + errCode + " returnValue: " + returnValue); -} - -function testStringTransactionCallback(errCode: number) -{ - console.log("errCode: " + errCode); -} - -function jsProxyTriggerCppStub() -{ - let nativeObj = nativeMgr.GetNativeObject(); - let tsProxy = new IdlTestServiceProxy(nativeObj); - // Call testIntTransaction. - tsProxy.testIntTransaction(10, testIntTransactionCallback); - - // Call testStringTransaction. - tsProxy.testStringTransaction("test", testIntTransactionCallback); -} -``` diff --git a/en/application-dev/Readme-EN.md b/en/application-dev/Readme-EN.md index f3fa0e7ac0e9b829f2418e4b1bf96001e66553d2..dba77cf37aab62a7bb4d33b367839a0c0c88bc4e 100644 --- a/en/application-dev/Readme-EN.md +++ b/en/application-dev/Readme-EN.md @@ -8,14 +8,14 @@ - Quick Start - Getting Started - [Preparations](quick-start/start-overview.md) - - [Getting Started with eTS in Stage Model](quick-start/start-with-ets-stage.md) - - [Getting Started with eTS in FA Model](quick-start/start-with-ets-fa.md) + - [Getting Started with ArkTS in Stage Model](quick-start/start-with-ets-stage.md) + - [Getting Started with ArkTS in FA Model](quick-start/start-with-ets-fa.md) - [Getting Started with JavaScript in FA Model](quick-start/start-with-js-fa.md) - Development Fundamentals - [Application Package Structure Configuration File (FA Model)](quick-start/package-structure.md) - [Application Package Structure Configuration File (Stage Model)](quick-start/stage-structure.md) - [SysCap](quick-start/syscap.md) - - [HarmonyAppProvision Configuration File](quick-start/app-provision-structure.md) + - Development - [Ability Development](ability/Readme-EN.md) - [UI Development](ui/Readme-EN.md) @@ -26,6 +26,7 @@ - [Security](security/Readme-EN.md) - [Connectivity](connectivity/Readme-EN.md) - [Data Management](database/Readme-EN.md) + - [File Management](file-management/Readme-EN.md) - [Telephony](telephony/Readme-EN.md) - [Task Management](task-management/Readme-EN.md) - [Device Management](device/Readme-EN.md) diff --git a/en/application-dev/ability-deprecated/Readme-EN.md b/en/application-dev/ability-deprecated/Readme-EN.md new file mode 100644 index 0000000000000000000000000000000000000000..5c803a47558bbd52765090debe162dbecd996ae6 --- /dev/null +++ b/en/application-dev/ability-deprecated/Readme-EN.md @@ -0,0 +1,25 @@ +# Ability Development + +> **NOTE**
+> This folder is deprecated. Read [Application Models](../application-models/Readme-EN.md) instead. + +- [Ability Framework Overview](ability-brief.md) +- [Context Usage](context-userguide.md) +- FA Model + - [FA Model Overview](fa-brief.md) + - [Page Ability Development](fa-pageability.md) + - [Service Ability Development](fa-serviceability.md) + - [Data Ability Development](fa-dataability.md) + - [FA Widget Development](fa-formability.md) +- Stage Model + - [Stage Model Overview](stage-brief.md) + - [Ability Development](stage-ability.md) + - [Service Extension Ability Development](stage-serviceextension.md) + - [Ability Continuation Development](stage-ability-continuation.md) + - [Ability Call Development](stage-call.md) + - [Stage Widget Development](stage-formextension.md) +- Other + - [WantAgent Development](wantagent.md) + - [Ability Assistant Usage](ability-assistant-guidelines.md) + - [ContinuationManager Development](continuationmanager.md) + - [Test Framework Usage](ability-delegator.md) diff --git a/en/application-dev/ability-deprecated/ability-assistant-guidelines.md b/en/application-dev/ability-deprecated/ability-assistant-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..d2e45f5d5492c23bcce0ec48674427df2cb2b765 --- /dev/null +++ b/en/application-dev/ability-deprecated/ability-assistant-guidelines.md @@ -0,0 +1,107 @@ +# Ability Assistant Usage + +The ability assistant enables you to start applications, atomic services, and test cases and debug applications. By using this tool, you can send commands in the hdc shell to perform various system operations, such as starting abilities, forcibly stopping processes, and printing ability information. + +## Query-related Commands + +- **help** + + Displays help information for the ability assistant. + + **Return value** + + Returns the help information. + + **Method** + + ``` + aa help + ``` + +## Ability-related Commands + +- **start** + + Starts an ability. + + | Name | Description | + | --------- | -------------------------- | + | -h/--help | Help information. | + | -d | Device ID. This parameter is optional. | + | -a | Ability name. This parameter is mandatory.| + | -b | Bundle name. This parameter is mandatory. | + | -D | Debugging mode. This parameter is optional. | + + **Return value** + + Returns "start ability successfully." if the ability is started; returns "error: failed to start ability." otherwise. + + **Method** + + ``` + aa start [-d ] -a -b [-D] + ``` + +- **stop-service** + + Stops a Service ability. + + | Name | Description | + | --------- | ------------------------ | + | -h/--help | Help information. | + | -d | Device ID. This parameter is optional. | + | -a | Ability name. This parameter is mandatory.| + | -b | Bundle name. This parameter is mandatory. | + + **Return value** + + Returns "stop service ability successfully." if the Service ability is stopped; returns "error: failed to stop service ability." otherwise. + + **Method** + + ``` + aa stop-service [-d ] -a -b + ``` + +- **dump** + + Prints ability-related information. + + | Name | Level-2 Parameter | Description | + | ----------------- | -------------------- | ------------------------------------------------------------ | + | -h/--help | - | Prints help information. | + | -a/--all | - | Prints ability information in all missions. | + | -l/--mission-list | type (All logs are printed if this parameter is left unspecified.)| Prints mission stack information.
The following values are available for **type**:
- NORMAL
- DEFAULT_STANDARD
- DEFAULT_SINGLE
- LAUNCHER | + | -e/--extension | elementName | Prints extended component information. | + | -u/--userId | UserId | Prints stack information of a specified user ID. This parameter must be used together with other parameters.
Example commands: aa **dump -a -u 100** and **aa dump -d -u 100**.| + | -d/--data | - | Prints Data ability information. | + | -i/--ability | AbilityRecord ID | Prints detailed information about a specified ability. | + | -c/--client | - | Prints detailed ability information. This parameter must be used together with other parameters.
Example commands: **aa dump -a -c** and **aa dump -i 21 -c**.| + + **Method** + + ``` + aa dump -a + ``` + ![aa-dump-a](figures/aa-dump-a.PNG) + ``` + aa dump -l + ``` + ![aa-dump-l](figures/aa-dump-l.PNG) + ``` + aa dump -i 12 + ``` + ![aa-dump-i](figures/aa-dump-i.PNG) +- **force-stop** + + Forcibly stops a process based on the bundle name. + + **Return value** + + Returns "force stop process successfully." if the process is forcibly stopped; returns "error: failed to force stop process." otherwise. + + **Method** + + ``` + aa force-stop + ``` diff --git a/en/application-dev/ability-deprecated/ability-brief.md b/en/application-dev/ability-deprecated/ability-brief.md new file mode 100644 index 0000000000000000000000000000000000000000..867e2c750a7d98b7964b037dcb809954fb5b40fb --- /dev/null +++ b/en/application-dev/ability-deprecated/ability-brief.md @@ -0,0 +1,34 @@ +# Ability Framework Overview + +Ability is the basic abstraction of applications in OpenHarmony. + +Each ability is an application component that provides an independent service and is the minimum unit for the system to schedule an application. An application can contain one or more **Ability** instances. + +The ability framework model has two forms: + +- FA model, which is available for application development using API version 8 and earlier versions. In the FA model, there are PageAbility, ServiceAbility, DataAbility, and FormAbility. +- Stage model, which is introduced since API version 9. In the stage model, there are two classes: UIAbility and ExtensionAbility. ExtensionAbility is further extended to ServiceExtensionAbility, FormExtensionAbility, DataShareExtensionAbility, and more. + +Starting from API version 9, the stage model is recommended. + +The stage model is designed to make it easier to develop complex applications in the distributed environment. The table below lists the design differences between the two models. + +| Item | FA Model | Stage Model | +| -------------- | ------------------------------------------------------------ | -------------------------------------------------------- | +| Application component development mode | Web-like development | Object-oriented development | +| Engine instance | Each **Ability** instance exclusively occupies a VM instance. | Multiple **Ability** instances share a VM instance. | +| Intra-process object sharing| Not supported | Supported | +| Bundle description file | The **config.json** file is used to describe the HAP and component information. Each component must use a fixed file name.| The **module.json5** file is used to describe the HAP and component information. The entry file name can be specified.| +| Component | Four types of components are provided: PageAbility (used for UI page display), ServiceAbility (used to provide services), DataAbility (used for data sharing), and FormAbility (used to provide widgets).| Two types of components are provided: UIAbility (used for UI page display) and ExtensionAbility (scenario-based service extension). | + +In addition, the following differences exist in the development process: + +* Different ability types + + ![favsstage](figures/favsstage.png) + +* Different ability lifecycles + + ![lifecycle](figures/lifecycle.png) + +For details about the two models, see [FA Model Overview](fa-brief.md) and [Stage Model Overview](stage-brief.md). diff --git a/en/application-dev/ability-deprecated/ability-delegator.md b/en/application-dev/ability-deprecated/ability-delegator.md new file mode 100644 index 0000000000000000000000000000000000000000..b32d472176a5b6270fece94ae4bd8ae9a7bd73fa --- /dev/null +++ b/en/application-dev/ability-deprecated/ability-delegator.md @@ -0,0 +1,181 @@ +# Test Framework Usage + +## Overview +The delegator test framework provides a self-test environment for OpenHarmony applications. Using this framework, you can start an ability, schedule its lifecycle, listen for its state changes, run a shell command, and print the test result. + +## Constraints + +The APIs provided by the test framework can be used only in the test HAP. They take effect only after the test framework is started. + + +## Starting the Test Framework + +The test framework can be started in either of the following ways: + +- Method 1: Run the `aa test` command. +- Method 2: Use DevEco Studio. + +### Running aa test + +To start the test framework, specify the **TestRunner** and the package name or module name of the HAP where the **TestRunner** is located. + +An example command in the FA model is as follows: + +```javascript +aa test -b BundleName -p com.example.myapplicationfaets -s unittest OpenHarmonyTestRunner -s class ActsAbilityTest -w 20 +``` + +An example command in the stage model is as follows: +```javascript +aa test -b BundleName -m com.example.myapplicationfaets -s unittest OpenHarmonyTestRunner -s class ActsAbilityTest -w 20 +``` +| Parameter | Mandatory| Description | +| --------------- | -------- | ------------------------------------------------------------ | +| -b | Yes | Bundle name of the HAP where the **TestRunner** is located. | +| -p | Yes | Package name of the HAP where the **TestRunner** is located. This parameter is used by the FA model. | +| -m | Yes | Module name of the HAP where the **TestRunner** is located. This parameter is used by the stage model. | +| -s unittest | Yes | Name of the **TestRunner** to be used. The TestRunner name must be the same as the file name. | +| -w | No | Timeout interval of a test case, in seconds. If this parameter is not specified or is set to a value less than or equal to **0**, the test framework exits only after **finishTest** is invoked.| +| -s \\ | No | **-s** can be followed by any key-value pair obtained through **AbilityDelegatorArgs.parameters**. For example, in **-s classname myTest**, **-s classname** is the key and **myTest** is the value.| +| -D | No | Debug mode for starting the tested application.| +| -h | No | Help information.| + +### Using DevEco Studio + +For details about how to use DevEco Studio to start the test framework, see [OpenHarmony Test Framework](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-openharmony-test-framework-0000001263160453#section1034420367508). + +## Introduction to TestRunner + +**TestRunner** is the entry class of the test framework test process. When the test process is started, the system calls related APIs in **TestRunner**. You need to inherit this class and override the **onPrepare** and **onRun** APIs. When creating an application template, DevEco Studio initializes the default **TestRunner** and starts the default **TestAbility** in the **onRun** API. You can modify the test code of **TestAbility** or override **onPrepare** and **onRun** in **TestRunner** to implement your own test code. For details, see [TestRunner](../reference/apis/js-apis-application-testRunner.md). + +## Introduction to AbilityDelegatorRegistry + +**AbilityDelegatorRegistry** is the **AbilityDelegator** repository class provided by the test framework. You can use **AbilityDelegatorRegistry** to obtain an **AbilityDelegator** instance and the input and generated parameters **AbilityDelegatorArgs** during the test. You can use **AbilityDelegator** to invoke the function set provided by the test framework for testing and verification. For details, see [AbilityDelegatorRegistry](../reference/apis/js-apis-application-abilityDelegatorRegistry.md). + +## Introduction to AbilityDelegatorArgs + +**AbilityDelegatorArgs** is a test parameter class provided by the test framework. You can use **AbilityDelegatorArgs** to obtain the parameters passed and generated during the test. For details, see [AbilityDelegatorArgs](../reference/apis/js-apis-inner-application-abilityDelegatorArgs.md). + +## Introduction to AbilityMonitor + +**AbilityMonitor** is provided by the test framework for binding to and listening for abilities. You can use **AbilityMonitor** to bind to an **Ability** instance and add **AbilityMonitor** to the listening list. When **AbilityMonitor** is bound to an ability, the creation and lifecycle changes of the ability will trigger the related callback in **AbilityMonitor**. You can test and verify the ability in these callbacks. For details, see [AbilityMonitor](../reference/apis/js-apis-inner-application-abilityMonitor.md). + +**Example** + +```javascript +import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' + +function onAbilityCreateCallback(data) { + console.info("onAbilityCreateCallback"); +} + +var monitor = { + abilityName: "abilityname", + onAbilityCreate: onAbilityCreateCallback +} + +var abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); +abilityDelegator.addAbilityMonitor(monitor).then(() => { + console.info("addAbilityMonitor promise"); +}); +``` + +## Introduction to AbilityDelegator + +**AbilityDelegator** is a main function class of the test framework. It provides the functions of starting an ability, obtaining an **Ability** instance, scheduling the ability lifecycle, listening for the ability state, and printing test results. + +**Modules to Import** + +```javascript +import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' +``` + +```javascript +var abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() +``` + +### Starting an Ability and Listening for the Ability State + +Use **AbilityDelegator** and **AbilityMonitor** to start an ability, obtain an **Ability** instance, and listen for the ability state. + +**Example** + +```javascript +var abilityDelegator; +var ability; +var timeout = 100; + +function onAbilityCreateCallback(data) { + console.info("onAbilityCreateCallback"); +} + +var monitor = { + abilityName: "abilityname", + onAbilityCreate: onAbilityCreateCallback +} + +abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); +abilityDelegator.waitAbilityMonitor(monitor, timeout, (err, data) => { + ability = data; + console.info("waitAbilityMonitor callback"); +}); + +var want = { + bundleName: "bundleName", + abilityName: "abilityName" +}; +abilityDelegator.startAbility(want, (err, data) => { + console.info("startAbility callback"); +}); +``` + +### Scheduling the Ability Lifecycle + +**AbilityDelegator** provides APIs to display and schedule the ability lifecycle and supports the foreground and background. It works with **AbilityMonitor** to listen for the ability lifecycle. For details, see [AbilityDelegator](../reference/apis/js-apis-inner-application-abilityDelegator.md). + +### Running a Shell Command + +**AbilityDelegator** provides APIs to run shell commands in the test environment. + +**Example** + +```javascript +var abilityDelegator; +var cmd = "cmd"; +abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); +abilityDelegator.executeShellCommand(cmd, (err, data) => { + console.info("executeShellCommand callback"); +}); +``` + +### Printing Log Information + +**AbilityDelegator** provides APIs for printing log information. You can call any API in the test code to print process logs to the unit test console. + +**Example** + +```javascript +var abilityDelegator; +var msg = "msg"; + +abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); +abilityDelegator.print(msg, (err) => { + console.info("print callback"); +}); +``` + +### Finishing the Test and Printing Log Information + +**AbilityDelegator** provides the APIs for actively finishing the test. You can call any API in test code to finish the test and print logs to the unit test console. + +**Example** + +```javascript +var abilityDelegator; +var msg = "msg"; + +abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); +abilityDelegator.finishTest(msg, 0, (err) => { + console.info("finishTest callback"); +}); +``` diff --git a/en/application-dev/ability-deprecated/context-userguide.md b/en/application-dev/ability-deprecated/context-userguide.md new file mode 100644 index 0000000000000000000000000000000000000000..ac65d92cb9422d040ff16cab1640cd1f9bed5d5c --- /dev/null +++ b/en/application-dev/ability-deprecated/context-userguide.md @@ -0,0 +1,318 @@ +# Context Usage + +## Context Overview + +**Context** provides the capability of obtaining contextual information of an application. + + The OpenHarmony application framework has two models: Feature Ability (FA) model and stage model. Correspondingly, there are two sets of context mechanisms. **application/BaseContext** is a common context base class. It uses the **stageMode** attribute to specify whether the context is used for the stage model. + +- FA model + +Only the methods in **app/Context** can be used for the context in the FA model. Both the application-level context and ability-level context are instances of this type. If an ability-level method is invoked in the application-level context, an error occurs. Therefore, you must pay attention to the actual meaning of the **Context** instance. + +- Stage model + + The stage model has the following types of contexts: **application/Context**, **application/ApplicationContext**, **application/AbilityStageContext**, **application/ExtensionContext**, **application/AbilityContext**, and **application/FormExtensionContext**. For details about these contexts and how to use them, see [Context in the Stage Model](#context-in-the-stage-model). + +![contextIntroduction](figures/contextIntroduction.png) + +## Context in the FA Model + +Only the methods in **app/Context** can be used for the context in the FA model. + +The FA model has only one context definition. All capabilities in the context are provided through methods. The context uses these methods to extend the capabilities of the FA. + +**d.ts statement** + +https://gitee.com/openharmony/interface_sdk-js/blob/master/api/app/context.d.ts + +**Example** + +```javascript +import featureAbility from '@ohos.ability.featureAbility' +export default { + onCreate() { + // Obtain the context and call related APIs. + let context = featureAbility.getContext(); + context.getBundleName((data, bundleName)=>{ + console.info("ability bundleName:" + bundleName) + }); + console.info('Application onCreate') + }, + onDestroy() { + console.info('Application onDestroy') + }, +} +``` + +### Common Context-related Methods in the FA Model +The following context-related methods are available in the FA model: +```javascript +setDisplayOrientation(orientation: bundle.DisplayOrientation, callback: AsyncCallback): void +setDisplayOrientation(orientation: bundle.DisplayOrientation): Promise; +``` +The methods are used to set the display orientation of the current ability. + +**Example** +```javascript +import featureAbility from '@ohos.ability.featureAbility' +import bundle from '@ohos.bundle'; + +export default { + onCreate() { + // Obtain the context and call related APIs. + let context = featureAbility.getContext(); + context.setDisplayOrientation(bundle.DisplayOrientation.LANDSCAPE).then(() => { + console.log("Set display orientation.") + }) + console.info('Application onCreate') + }, + onDestroy() { + console.info('Application onDestroy') + }, +} +``` + +## Context in the Stage Model + +The following describes the contexts provided by the stage model in detail. + +### application/Context + +**application/Context** is the base class context. It provides basic application information, such as **resourceManager**, **applicationInfo**, **cacheDir**, and **area**. It also provides basic application methods such as **createModuleContext**. + +**d.ts statement** + +https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/Context.d.ts + +### application/ApplicationContext + +**application/ApplicationContext** is an application-level context. In addition to the capabilities provided by the base class context, the application-level context provides **registerAbilityLifecycleCallback** and **unregisterAbilityLifecycleCallback** to monitor the ability lifecycle in a process. + +**How to Obtain** + +Obtain the context by calling **context.getApplicationContext()** in **Ability**. + +**Example** + +```javascript +import Ability from "@ohos.application.Ability"; + +var lifecycleid; + +export default class MainAbility extends Ability { + onCreate() { + console.log("MainAbility onCreate") + let AbilityLifecycleCallback = { + onAbilityCreate(ability){ + console.log("AbilityLifecycleCallback onAbilityCreate ability:" + JSON.stringify(ability)); + }, + onWindowStageCreate(ability, windowStage){ + console.log("AbilityLifecycleCallback onWindowStageCreate ability:" + JSON.stringify(ability)); + console.log("AbilityLifecycleCallback onWindowStageCreate windowStage:" + JSON.stringify(windowStage)); + }, + onWindowStageActive(ability, windowStage){ + console.log("AbilityLifecycleCallback onWindowStageActive ability:" + JSON.stringify(ability)); + console.log("AbilityLifecycleCallback onWindowStageActive windowStage:" + JSON.stringify(windowStage)); + }, + onWindowStageInactive(ability, windowStage){ + console.log("AbilityLifecycleCallback onWindowStageInactive ability:" + JSON.stringify(ability)); + console.log("AbilityLifecycleCallback onWindowStageInactive windowStage:" + JSON.stringify(windowStage)); + }, + onWindowStageDestroy(ability, windowStage){ + console.log("AbilityLifecycleCallback onWindowStageDestroy ability:" + JSON.stringify(ability)); + console.log("AbilityLifecycleCallback onWindowStageDestroy windowStage:" + JSON.stringify(windowStage)); + }, + onAbilityDestroy(ability){ + console.log("AbilityLifecycleCallback onAbilityDestroy ability:" + JSON.stringify(ability)); + }, + onAbilityForeground(ability){ + console.log("AbilityLifecycleCallback onAbilityForeground ability:" + JSON.stringify(ability)); + }, + onAbilityBackground(ability){ + console.log("AbilityLifecycleCallback onAbilityBackground ability:" + JSON.stringify(ability)); + }, + onAbilityContinue(ability){ + console.log("AbilityLifecycleCallback onAbilityContinue ability:" + JSON.stringify(ability)); + } + } + // 1. Obtain applicationContext through the context attribute. + let applicationContext = this.context.getApplicationContext(); + // 2. Use applicationContext to register and listen for the ability lifecycle in the application. + lifecycleid = applicationContext.registerAbilityLifecycleCallback(AbilityLifecycleCallback); + console.log("registerAbilityLifecycleCallback number: " + JSON.stringify(lifecycleid)); + }, + onDestroy() { + let applicationContext = this.context.getApplicationContext(); + applicationContext.unregisterAbilityLifecycleCallback(lifecycleid, (error, data) => { + console.log("unregisterAbilityLifecycleCallback success, err: " + JSON.stringify(error)); + }); + } +} +``` + +**d.ts statement** + +https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/ApplicationContext.d.ts + +### application/AbilityStageContext + +**application/AbilityStageContext** is the context for the HAP file. In addition to those provided by the base class **application/Context**, this context contains **HapModuleInfo** and **Configuration**. + +**How to Obtain** + +Obtain the context from the **context** attribute in **AbilityStage**. + +**Example** + +```javascript +export default class MyAbilityStage extends AbilityStage { + onCreate() { + // The context attribute is of the AbilityStageContext type. + console.log('HapModuleInfo is ' + this.context.currentHapModuleInfo); + } +} +``` + +**d.ts statement** + +https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/AbilityStageContext.d.ts + +### application/AbilityContext + +In the stage model, each ability has a context attribute. + +**Ability** provides methods to manage the ability lifecycle, and **AbilityContext** provides methods to operate abilities (such as **startAbility** and **connectAbility**). + +**How to Obtain** + +Obtain the context from the **context** attribute in **Ability**. + +**Example** + +```javascript +import Ability from '@ohos.application.Ability' + +export default class MainAbility extends Ability { + onCreate(want, launchParam) { + console.log("[Demo] MainAbility onCreate") + globalThis.abilityWant = want; + } + + onDestroy() { + console.log("[Demo] MainAbility onDestroy") + } + + onWindowStageCreate(windowStage) { + // Set the main page for this ability when the main window is created. + console.log("[Demo] MainAbility onWindowStageCreate") + + // Obtain AbilityContext and print the ability information. + let context = this.context; + console.log("[Demo] MainAbility bundleName " + context.abilityInfo.bundleName) + + windowStage.loadContent("pages/index", (err, data) => { + if (err.code) { + console.error('Failed to load the content. Cause:' + JSON.stringify(err)); + return; + } + console.info('Succeeded in loading the content. Data: ' + JSON.stringify(data)) + }); + } + + onWindowStageDestroy() { + // Release the UI related resources when the main window is destroyed. + console.log("[Demo] MainAbility onWindowStageDestroy") + } + + onForeground() { + // The ability is switched to run in the foreground. + console.log("[Demo] MainAbility onForeground") + } + + onBackground() { + // The ability is switched to run in the background. + console.log("[Demo] MainAbility onBackground") + } +}; +``` + +### application/FormExtensionContext + +For details, see [FormExtensionContext](../reference/apis/js-apis-inner-application-formExtensionContext.md). + +### Obtaining the Context on an ArkTS Page + +In the stage model, in the onWindowStageCreate lifecycle of an ability, you can call **SetUIContent** of **WindowStage** to load an ArkTS page. In some scenarios, you need to obtain the context on the page to call related APIs. + +**How to Obtain** + +Use the API described in the table below to obtain the context associated with an ArkTS page. + +| API | Description | +| :------------------------------------ | :--------------------------- | +| getContext(component: Object): Object | Obtains the **Context** object associated with a component on the page.| + +**Example** + +```ts +// MainAbility.ts +import Ability from '@ohos.application.Ability' + +export default class MainAbility extends Ability { + onCreate(want, launchParam) { + console.log("[Demo] MainAbility onCreate") + } + + onDestroy() { + console.log("[Demo] MainAbility onDestroy") + } + + onWindowStageCreate(windowStage) { + // Load the index page and pass the current Context object. + windowStage.setUIContent(this.context, "pages/index", null) + } + + onWindowStageDestroy() {} + + onForeground() {} + + onBackground() {} +}; +``` + +```ts +// pages/index.ets +import context from '@ohos.application.context' + +type Context = context.Context + +@Entry +@Component +struct Index { + build() { + Row() { + Column() { + Text('GetContext') + .fontSize(50) + .fontWeight(FontWeight.Bold) + .onClick(() => { + // Obtain the Context object associated with the current component. + var context : Context = getContext(this) as Context + console.info("CacheDir:" + context.cacheDir) + }) + } + .width('100%') + } + .height('100%') + } +} +``` + +## Common Incorrect Usage + +**Error 1: Use globalThis to obtain the context in the stage model.** + +**Reason** + +In the FA model, each ability instance has a JS VM instance. Therefore, a global ability instance can be obtained from the **global** object of the JS engine. In the stage model, where all the processes of an application share a JS VM instance, there is no global ability instance, and using **globalThis** may cause an error or crash. diff --git a/en/application-dev/ability-deprecated/continuationmanager.md b/en/application-dev/ability-deprecated/continuationmanager.md new file mode 100644 index 0000000000000000000000000000000000000000..0ba79f95acf165d604d8f854832703d7fc4af3f8 --- /dev/null +++ b/en/application-dev/ability-deprecated/continuationmanager.md @@ -0,0 +1,277 @@ +# ContinuationManager Development + +> **NOTE** +> +> Currently, the **ContinuationManager** module is not available for application development. Its APIs are mainly used to start the device selection module. + +## When to Use +Users are using two or more devices to experience an all-scenario, multi-device lifestyle. Each type of device has its unique advantages and disadvantages specific to scenarios. The ability continuation capability breaks boundaries of devices and enables multi-device collaboration, achieving precise control, universal coordination, and seamless hops of user applications. + +As the entry of the ability continuation capability, **continuationManager** is used to start the device selection module for the user to select the target device. After a device is selected, information about the selected device is returned to the user. The user can then initiate cross-device continuation or collaboration based on the device information. + +![continuationManager](figures/continuationManager.png) + +## Available APIs +| API | Description| +| ---------------------------------------------------------------------------------------------- | ----------- | +| registerContinuation(callback: AsyncCallback\): void | Registers the continuation management service and obtains a token. This API does not involve any filter parameters and uses an asynchronous callback to return the result.| +| registerContinuation(options: ContinuationExtraParams, callback: AsyncCallback\): void | Registers the continuation management service and obtains a token. This API uses an asynchronous callback to return the result.| +| registerContinuation(options?: ContinuationExtraParams): Promise\ | Registers the continuation management service and obtains a token. This API uses a promise to return the result.| +| on(type: "deviceSelected", token: number, callback: Callback\>): void | Subscribes to device connection events. This API uses an asynchronous callback to return the result.| +| on(type: "deviceUnselected", token: number, callback: Callback\>): void | Subscribes to device disconnection events. This API uses an asynchronous callback to return the result.| +| off(type: "deviceSelected", token: number): void | Unsubscribes from device connection events.| +| off(type: "deviceUnselected", token: number): void | Unsubscribes from device disconnection events.| +| startContinuationDeviceManager(token: number, callback: AsyncCallback\): void | Starts the device selection module to show the list of available devices. This API does not involve any filter parameters and uses an asynchronous callback to return the result.| +| startContinuationDeviceManager(token: number, options: ContinuationExtraParams, callback: AsyncCallback\): void | Starts the device selection module to show the list of available devices. This API uses an asynchronous callback to return the result.| +| startContinuationDeviceManager(token: number, options?: ContinuationExtraParams): Promise\ | Starts the device selection module to show the list of available devices. This API uses a promise to return the result.| +| updateContinuationState(token: number, deviceId: string, status: DeviceConnectState, callback: AsyncCallback\): void | Instructs the device selection module to update the device connection state. This API uses an asynchronous callback to return the result.| +| updateContinuationState(token: number, deviceId: string, status: DeviceConnectState): Promise\ | Instructs the device selection module to update the device connection state. This API uses a promise to return the result.| +| unregisterContinuation(token: number, callback: AsyncCallback\): void | Deregisters the continuation management service. This API uses an asynchronous callback to return the result.| +| unregisterContinuation(token: number): Promise\ | Deregisters the continuation management service. This API uses a promise to return the result.| + +## How to Develop +1. Import the **continuationManager** module. + + ```ts + import continuationManager from '@ohos.continuation.continuationManager'; + ``` + +2. Apply for the **DISTRIBUTED_DATASYNC** permission. + + The permission application operation varies according to the ability model in use. In the FA mode, add the required permission in the `config.json` file, as follows: + + ```json + { + "module": { + "reqPermissions": [ + { + "name": "ohos.permission.DISTRIBUTED_DATASYNC" + } + ] + } + } + ``` + + This permission must also be granted by the user through a dialog box when the application is started for the first time. The sample code is as follows: + + ```ts + import abilityAccessCtrl from "@ohos.abilityAccessCtrl"; + import bundle from '@ohos.bundle'; + import featureAbility from '@ohos.ability.featureAbility'; + + async function requestPermission() { + let permissions: Array = [ + "ohos.permission.DISTRIBUTED_DATASYNC" + ]; + let needGrantPermission: boolean = false; + let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); + let applicationInfo = await bundle.getApplicationInfo('ohos.samples.etsDemo', 0, 100); + for (let i = 0; i < permissions.length; i++) { + let result = await atManager.verifyAccessToken(applicationInfo.accessTokenId, permissions[i]); + // Check whether the permission is granted. + if (result == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { + needGrantPermission = true; + break; + } + } + // If the permission is not granted, call requestPermissionsFromUser to apply for the permission. + if (needGrantPermission) { + await featureAbility.getContext().requestPermissionsFromUser(permissions, 1); + } else { + console.info('app permission already granted'); + } + } + ``` + + In the stage model, add the required permission in the `module.json5` file. The sample code is as follows: + + ```json + { + "module": { + "requestPermissions": [ + { + "name": "ohos.permission.DISTRIBUTED_DATASYNC" + } + ] + } + } + ``` + + ```ts + import abilityAccessCtrl from "@ohos.abilityAccessCtrl"; + import bundle from '@ohos.bundle'; + + async function requestPermission() { + let permissions: Array = [ + "ohos.permission.DISTRIBUTED_DATASYNC" + ]; + let needGrantPermission: boolean = false; + let atManger: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); + let applicationInfo = await bundle.getApplicationInfo('ohos.samples.continuationmanager', 0, 100); + for (const permission of permissions) { + try { + let grantStatus = await atManger.verifyAccessToken(applicationInfo.accessTokenId, permission); + // Check whether the permission is granted. + if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) { + needGrantPermission = true; + break; + } + } catch (err) { + console.error('app permission query grant status error' + JSON.stringify(err)); + needGrantPermission = true; + break; + } + } + // If the permission is not granted, call requestPermissionsFromUser to apply for the permission. + if (needGrantPermission) { + try { + // globalThis.context is Ability.context, which must be assigned a value in the MainAbility.ts file in advance. + await globalThis.context.requestPermissionsFromUser(permissions); + } catch (err) { + console.error('app permission request permissions error' + JSON.stringify(err)); + } + } else { + console.info('app permission already granted'); + } + } + ``` + +3. Register the continuation management service and obtain a token. + + The sample code is as follows: + + ```ts + let token: number = -1; // Used to save the token returned after the registration. The token will be used when listening for device connection/disconnection events, starting the device selection module, and updating the device connection state. + try { + continuationManager.registerContinuation().then((data) => { + console.info('registerContinuation finished, ' + JSON.stringify(data)); + token = data; // Obtain a token and assign a value to the token variable. + }).catch((err) => { + console.error('registerContinuation failed, cause: ' + JSON.stringify(err)); + }); + } catch (err) { + console.error('registerContinuation failed, cause: ' + JSON.stringify(err)); + } + ``` + +4. Listen for the device connection/disconnection state. + + The sample code is as follows: + + ```ts + let remoteDeviceId: string = ""; // Used to save the information about the remote device selected by the user, which will be used for cross-device continuation or collaboration. + + try { + // The token parameter is the token obtained during the registration. + continuationManager.on("deviceSelected", token, (continuationResults) => { + console.info('registerDeviceSelectedCallback len: ' + continuationResults.length); + if (continuationResults.length <= 0) { + console.info('no selected device'); + return; + } + remoteDeviceId = continuationResults[0].id; // Assign the deviceId of the first selected remote device to the remoteDeviceId variable. + + // Pass the remoteDeviceId parameter to want. + let want = { + deviceId: remoteDeviceId, + bundleName: 'ohos.samples.continuationmanager', + abilityName: 'MainAbility' + }; + globalThis.abilityContext.startAbility(want).then((data) => { + console.info('StartRemoteAbility finished, ' + JSON.stringify(data)); + }).catch((err) => { + console.error('StartRemoteAbility failed, cause: ' + JSON.stringify(err)); + }); + }); + } catch (err) { + console.error('on failed, cause: ' + JSON.stringify(err)); + } + ``` + + The preceding multi-device collaboration operation is performed across devices in the stage model. For details about this operation in the FA model, see [Page Ability Development](fa-pageability.md). + + You can also instruct the device selection module to update the device connection state. The sample code is as follows: + + ```ts + // Set the device connection state. + let deviceConnectStatus: continuationManager.DeviceConnectState = continuationManager.DeviceConnectState.CONNECTED; + + // The token parameter is the token obtained during the registration, and the remoteDeviceId parameter is the remoteDeviceId obtained. + try { + continuationManager.updateContinuationState(token, remoteDeviceId, deviceConnectStatus).then((data) => { + console.info('updateContinuationState finished, ' + JSON.stringify(data)); + }).catch((err) => { + console.error('updateContinuationState failed, cause: ' + JSON.stringify(err)); + }); + } catch (err) { + console.error('updateContinuationState failed, cause: ' + JSON.stringify(err)); + } + ``` + + Listen for the device disconnection state so that the user can stop cross-device continuation or collaboration in time. The sample code is as follows: + + ```ts + try { + // The token parameter is the token obtained during the registration. + continuationManager.on("deviceUnselected", token, (continuationResults) => { + console.info('onDeviceUnselected len: ' + continuationResults.length); + if (continuationResults.length <= 0) { + console.info('no unselected device'); + return; + } + + // Update the device connection state. + let unselectedDeviceId: string = continuationResults[0].id; // Assign the deviceId of the first deselected remote device to the unselectedDeviceId variable. + let deviceConnectStatus: continuationManager.DeviceConnectState = continuationManager.DeviceConnectState.DISCONNECTING; // Device disconnected. + + // The token parameter is the token obtained during the registration, and the unselectedDeviceId parameter is the unselectedDeviceId obtained. + continuationManager.updateContinuationState(token, unselectedDeviceId, deviceConnectStatus).then((data) => { + console.info('updateContinuationState finished, ' + JSON.stringify(data)); + }).catch((err) => { + console.error('updateContinuationState failed, cause: ' + JSON.stringify(err)); + }); + }); + } catch (err) { + console.error('updateContinuationState failed, cause: ' + JSON.stringify(err)); + } + ``` + +5. Start the device selection module to show the list of available devices on the network. + + The sample code is as follows: + + ```ts + // Filter parameters. + let continuationExtraParams = { + deviceType: ["00E"], // Device type. + continuationMode: continuationManager.ContinuationMode.COLLABORATION_SINGLE // Single-choice mode of the device selection module. + }; + + try { + // The token parameter is the token obtained during the registration. + continuationManager.startContinuationDeviceManager(token, continuationExtraParams).then((data) => { + console.info('startContinuationDeviceManager finished, ' + JSON.stringify(data)); + }).catch((err) => { + console.error('startContinuationDeviceManager failed, cause: ' + JSON.stringify(err)); + }); + } catch (err) { + console.error('startContinuationDeviceManager failed, cause: ' + JSON.stringify(err)); + } + ``` + +6. If you do not need to perform cross-device migration or collaboration operations, you can deregister the continuation management service, by passing the token obtained during the registration. + + The sample code is as follows: + + ```ts + try { + // The token parameter is the token obtained during the registration. + continuationManager.unregisterContinuation(token).then((data) => { + console.info('unregisterContinuation finished, ' + JSON.stringify(data)); + }).catch((err) => { + console.error('unregisterContinuation failed, cause: ' + JSON.stringify(err)); + }); + } catch (err) { + console.error('unregisterContinuation failed, cause: ' + JSON.stringify(err)); + } + ``` diff --git a/en/application-dev/ability-deprecated/fa-brief.md b/en/application-dev/ability-deprecated/fa-brief.md new file mode 100644 index 0000000000000000000000000000000000000000..5ad79cfe259f1fb9cf865b9d6f496c0f31c47ae0 --- /dev/null +++ b/en/application-dev/ability-deprecated/fa-brief.md @@ -0,0 +1,43 @@ +# FA Model Overview + +## Overall Architecture + +Ability is the entry for application development in OpenHarmony. + +The core of ability development is the processing on ability lifecycle callbacks. + +The Feature Ability (FA) model can be used only for application development using API version 8 and earlier versions. In this model, there are PageAbility, ServiceAbility, DataAbility, and FormAbility. +- PageAbility implements the ArkUI and provides the capability for interacting with users. +- ServiceAbility does not have a UI. It runs in the background and provides custom services for other abilities to invoke. +- DataAbility does not have a UI. It runs in the background and enables other abilities to insert, delete, and query data. +- FormAbility is used to implement widgets, a new UI display form available on OpenHarmony devices. + +> Note: Starting from API version 9, the stage model is recommended for application development. + +## Lifecycle + +Among all abilities, PageAbility has the most complex lifecycle, because it has a UI and acts as a touchpoint for interacting with users. +**The following figure shows the lifecycle of PageAbility.** + +![fa-pageAbility-lifecycle](figures/fa-pageAbility-lifecycle.png) + +The other abilities do not involve foreground and background switch or the **onShow** and **onHide** callbacks. +You can override the lifecycle callbacks in **app.js** or **app.ets** to process application logic. + +The **app.js** file provides only the **onCreate** and **onDestroy** callbacks, and the **app.ets** file provides the callbacks covering the entire lifecycle. + +## Process and Thread Model + +Each application runs in a process. In the FA model, each ability runs in an independent VM. + +When an ability is started, an application process as well as a thread for this ability is created. For an application that has multiple abilities, each ability runs in an independent thread. In the FA model, each ability is bound to an independent VM instance. In this way, abilities are isolated from each other. + +![fa-threading-model](figures/fa-threading-model.png) + +## Application Package Structure + +For details about the project directory structure of the FA model, see [OpenHarmony Project Overview](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-project-overview-0000001218440650#section4154183910141). + +For details about how to configure the application package structure of the FA model, see [Application Package Structure Configuration File](../quick-start/application-configuration-file-overview-fa.md). + + \ No newline at end of file diff --git a/en/application-dev/ability-deprecated/fa-dataability.md b/en/application-dev/ability-deprecated/fa-dataability.md new file mode 100644 index 0000000000000000000000000000000000000000..8d94e8f225a3966d676e6c7631968c25f5634531 --- /dev/null +++ b/en/application-dev/ability-deprecated/fa-dataability.md @@ -0,0 +1,310 @@ +# Data Ability Development + +## When to Use + +A Data ability helps applications manage access to data stored by themselves and other applications. It also provides APIs for sharing data with other applications either on the same device or across devices. + +Data ability providers can customize data access-related APIs such as data inserting, deleting, updating, and querying, as well as file opening, and share data with other applications through these open APIs. + +## URI Introduction + +A Uniform Resource Identifier (URI) is used to identify a specific data item, such as a table in the database or a file on the disk. URIs used in OpenHarmony comply with the commonly used URI standard. A URI consists of the components: + +![fa-dataability-uri](figures/fa-dataability-uri.png) + +- **scheme**: name of the scheme used by the Data ability. The value is fixed at **dataability**. +- **authority**: device ID. To access data on a remote device, set this component to the ID of the remote device. To access data on the local device, leave this component empty. +- **path**: location of the specific resource to access. +- **query**: query parameters. +- **fragment**: subordinate resources to access. + +Example URIs: + +- Cross-device communication: **dataability://***device_id***/***com.domainname.dataability.persondata***/***person***/***10* +- Local-device communication: **dataability:///***com.domainname.dataability.persondata***/***person***/***10* + +> **NOTE** +> +> In the case of local-device communication, **device_id** is empty, and therefore, there are three slashes (/) after **dataability:**. + +## Available APIs + +**Table 1** Data ability lifecycle APIs +|API|Description| +|:------|:------| +|onInitialized(info: AbilityInfo): void|Called during ability initialization to initialize the relational database (RDB).| +|update(uri: string, valueBucket: rdb.ValuesBucket, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback\): void|Updates data in the database.| +|query(uri: string, columns: Array\, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback\): void|Queries data in the database.| +|delete(uri: string, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback\): void|Deletes one or more data records from the database.| +|normalizeUri(uri: string, callback: AsyncCallback\): void|Normalizes the URI. A normalized URI applies to cross-device use, persistence, backup, and restore. When the context changes, it ensures that the same data item can be referenced.| +|batchInsert(uri: string, valueBuckets: Array\, callback: AsyncCallback\): void|Inserts multiple data records into the database.| +|denormalizeUri(uri: string, callback: AsyncCallback\): void|Converts a normalized URI generated by **normalizeUri** into a denormalized URI.| +|insert(uri: string, valueBucket: rdb.ValuesBucket, callback: AsyncCallback\): void|Inserts a data record into the database.| +|openFile(uri: string, mode: string, callback: AsyncCallback\): void|Opens a file.| +|getFileTypes(uri: string, mimeTypeFilter: string, callback: AsyncCallback\>): void|Obtains the MIME type of a file.| +|getType(uri: string, callback: AsyncCallback\): void|Obtains the MIME type matching the data specified by the URI.| +|executeBatch(ops: Array\, callback: AsyncCallback\>): void|Operates data in the database in batches.| +|call(method: string, arg: string, extras: PacMap, callback: AsyncCallback\): void|Calls a custom API.| + + +## How to Develop +### Creating a Data Ability + +1. To meet the basic requirements of the database storage service, implement the **Insert**, **Query**, **Update**, and **Delete** APIs in the **Data** class. The **BatchInsert** and **ExecuteBatch** APIs have already implemented the traversal logic, but not batch data processing. + + The following code snippet shows how to create a Data ability: + + ```javascript + import featureAbility from '@ohos.ability.featureAbility' + import dataAbility from '@ohos.data.dataAbility' + import dataRdb from '@ohos.data.rdb' + + const TABLE_NAME = 'book' + const STORE_CONFIG = { name: 'book.db' } + const SQL_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS book(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, introduction TEXT NOT NULL)' + let rdbStore: dataRdb.RdbStore = undefined + + export default { + onInitialized(abilityInfo) { + console.info('DataAbility onInitialized, abilityInfo:' + abilityInfo.bundleName) + let context = featureAbility.getContext() + dataRdb.getRdbStore(context, STORE_CONFIG, 1, (err, store) => { + console.info('DataAbility getRdbStore callback') + store.executeSql(SQL_CREATE_TABLE, []) + rdbStore = store + }); + }, + insert(uri, valueBucket, callback) { + console.info('DataAbility insert start') + rdbStore.insert(TABLE_NAME, valueBucket, callback) + }, + batchInsert(uri, valueBuckets, callback) { + console.info('DataAbility batch insert start') + for (let i = 0;i < valueBuckets.length; i++) { + console.info('DataAbility batch insert i=' + i) + if (i < valueBuckets.length - 1) { + rdbStore.insert(TABLE_NAME, valueBuckets[i], (err: any, num: number) => { + console.info('DataAbility batch insert ret=' + num) + }) + } else { + rdbStore.insert(TABLE_NAME, valueBuckets[i], callback) + } + } + }, + query(uri, columns, predicates, callback) { + console.info('DataAbility query start') + let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates) + rdbStore.query(rdbPredicates, columns, callback) + }, + update(uri, valueBucket, predicates, callback) { + console.info('DataAbilityupdate start') + let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates) + rdbStore.update(valueBucket, rdbPredicates, callback) + }, + delete(uri, predicates, callback) { + console.info('DataAbilitydelete start') + let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates) + rdbStore.delete(rdbPredicates, callback) + } + }; + ``` + +2. Configure the submodule. + + | JSON Field| Description | + | ------------ | ------------------------------------------------------------ | + | "name" | Ability name, corresponding to the **Data** class name derived from **Ability**. | + | "type" | Ability type, which is **Data** for a Data ability. | + | "uri" | URI used for communication. | + | "visible" | Whether the Data ability is visible to other applications. When this parameter is set to **true**, the Data ability can communicate with other applications.| + + **config.json configuration example** + + ```json + "abilities":[{ + "srcPath": "DataAbility", + "name": ".DataAbility", + "icon": "$media:icon", + "srcLanguage": "ets", + "description": "$string:description_dataability", + "type": "data", + "visible": true, + "uri": "dataability://ohos.samples.etsdataability.DataAbility" + }] + ``` + +### Accessing a Data ability +#### Development Preparations + +Import the basic dependency packages and obtain the URI string for communicating with the Data submodule. + +The basic dependency packages include: +- @ohos.ability.featureAbility +- @ohos.data.dataAbility +- @ohos.data.rdb + +#### Data Ability API Development + + +1. Create a Data ability helper. + + For details about the APIs provided by **DataAbilityHelper**, see [DataAbilityHelper Module](../reference/apis/js-apis-inner-ability-dataAbilityHelper.md). + ```js + // Different from the URI defined in the config.json file, the URI passed in the parameter has an extra slash (/), because there is a DeviceID parameter between the second and the third slash (/). + import featureAbility from '@ohos.ability.featureAbility' + import ohos_data_ability from '@ohos.data.dataAbility' + import ohos_data_rdb from '@ohos.data.rdb' + + var urivar = "dataability:///com.ix.DataAbility" + var DAHelper = featureAbility.acquireDataAbilityHelper( + urivar + ); + ``` +2. Construct RDB data. + ```js + var valuesBucket = {"name": "gaolu"} + var da = new ohos_data_ability.DataAbilityPredicates() + var valArray =new Array("value1"); + var cars = new Array({"batchInsert1" : "value1",}); + ``` +3. Use **insert** to insert data to the Data submodule. + ```js + // Callback mode: + DAHelper.insert( + urivar, + valuesBucket, + (error, data) => { + console.log("DAHelper insert result: " + data) + } + ); + ``` + + ```js + // Promise mode: + var datainsert = await DAHelper.insert( + urivar, + valuesBucket + ); + ``` +4. Use **delete** to delete data from the Data submodule. + ```js + // Callback mode: + DAHelper.delete( + urivar, + da, + (error, data) => { + console.log("DAHelper delete result: " + data) + } + ); + ``` + + ```js + // Promise mode: + var datadelete = await DAHelper.delete( + urivar, + da, + ); + ``` +5. Use **update** to update data in the Data submodule. + ```js + // Callback mode: + DAHelper.update( + urivar + valuesBucket, + da, + (error, data) => { + console.log("DAHelper update result: " + data) + } + ); + ``` + + ```js + // Promise mode: + var dataupdate = await DAHelper.update( + urivar, + valuesBucket, + da, + ); + ``` +6. Use **query** to query data in the Data submodule. + ```js + // Callback mode: + DAHelper.query( + urivar, + valArray, + da, + (error, data) => { + console.log("DAHelper query result: " + data) + } + ); + ``` + + ```js + // Promise mode: + var dataquery = await DAHelper.query( + urivar, + valArray, + da + ); + ``` +7. Use **batchInsert** to insert data in batches to the Data submodule. + ```js + // Callback mode: + DAHelper.batchInsert( + urivar, + cars, + (error, data) => { + console.log("DAHelper batchInsert result: " + data) + } + ); + ``` + + ```js + // Promise mode: + var databatchInsert = await DAHelper.batchInsert( + urivar, + cars + ); + ``` +8. Use **executeBatch** to process data in batches in the Data submodule. + ```js + // Callback mode: + DAHelper.executeBatch( + urivar, + [ + { + uri: urivar, + type: featureAbility.DataAbilityOperationType.TYPE_INSERT, + valuesBucket: {"executeBatch" : "value1",}, + predicates: da, + expectedCount:0, + predicatesBackReferences: null, + interrupted:true, + } + ], + (error, data) => { + console.log("DAHelper executeBatch result: " + data) + } + ); + ``` + + ```js + // Promise mode: + var dataexecuteBatch = await DAHelper.executeBatch( + urivar, + [ + { + uri: urivar, + type: featureAbility.DataAbilityOperationType.TYPE_INSERT, + valuesBucket: + { + "executeBatch" : "value1", + }, + predicates: da, + expectedCount:0, + predicatesBackReferences: null, + interrupted:true, + } + ] + ); + ``` diff --git a/en/application-dev/ability-deprecated/fa-formability.md b/en/application-dev/ability-deprecated/fa-formability.md new file mode 100644 index 0000000000000000000000000000000000000000..a91ca4b9baf98f32bad7ea081024d74949baf726 --- /dev/null +++ b/en/application-dev/ability-deprecated/fa-formability.md @@ -0,0 +1,404 @@ +# FA Widget Development + +## Widget Overview +A 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. + +A 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. + +Before you get started, it would be helpful if you have a basic understanding of the following concepts: +- Widget provider: an atomic service that provides the widget content to display and controls how widget components are laid out and how they interact with users. +- Widget host: an application that displays the widget content and controls the widget location. +- Widget Manager: a resident agent that provides widget management features such as periodic widget updates. + +> **NOTE** +> +> The widget host and provider do not need to be running all the time. The Widget Manager will start the widget provider to obtain widget information when a widget is added, deleted, or updated. + +You only need to develop the widget provider. The system automatically handles the work of the widget host and Widget Manager. + +The widget provider controls the widget content to display, the layout of components used in the widget, and click events bound to the components. + +## Development Overview + +Carry out the following operations to develop the widget provider based on the [FA model](fa-brief.md): + +1. Implement lifecycle callbacks by using the **LifecycleForm** APIs. +2. Create a **FormBindingData** instance. +3. Update a widget by using the **FormProvider** APIs. +4. Develop the widget UI pages. + +## Available APIs + +The table below describes the **LifecycleForm** APIs, which represent the lifecycle callbacks of a widget (known as a **Form** instance). + +**Table 1** LifecycleForm APIs + +| API | Description | +| :----------------------------------------------------------- | :------------------------------------------- | +| onCreate(want: Want): formBindingData.FormBindingData | Called to notify the widget provider that a widget has been created. | +| onCastToNormal(formId: string): void | Called to notify the widget provider that a temporary widget has been converted to a normal one.| +| onUpdate(formId: string): void | Called to notify the widget provider that a widget has been updated. | +| onVisibilityChange(newStatus: { [key: string]: number }): void | Called to notify the widget provider of the change in widget visibility. | +| onEvent(formId: string, message: string): void | Called to instruct the widget provider to receive and process a widget event. | +| onDestroy(formId: string): void | Called to notify the widget provider that a widget has been destroyed. | +| onAcquireFormState?(want: Want): formInfo.FormState | Called to instruct the widget provider to receive the status query result of a widget. | + +The table below describes the **FormProvider** APIs. For details, see [FormProvider](../reference/apis/js-apis-application-formProvider.md). + +**Table 2** FormProvider APIs + +| API | Description | +| :----------------------------------------------------------- | :------------------------------------------------ | +| setFormNextRefreshTime(formId: string, minute: number, callback: AsyncCallback<void>): void; | Sets the next refresh time for a widget. This API uses an asynchronous callback to return the result. | +| setFormNextRefreshTime(formId: string, minute: number): Promise<void>; | Sets the next refresh time for a widget. This API uses a promise to return the result.| +| updateForm(formId: string, formBindingData: FormBindingData, callback: AsyncCallback<void>): void; | Updates a widget. This API uses an asynchronous callback to return the result. | +| updateForm(formId: string, formBindingData: FormBindingData): Promise<void>; | Updates a widget. This API uses a promise to return the result. | + +## How to Develop + +### Implementing Lifecycle Callbacks + +To create an FA widget, you need to implement lifecycle callbacks using the **LifecycleForm** APIs. The sample code is as follows: + +1. Import the required modules. + + ```javascript + import formBindingData from '@ohos.application.formBindingData' + import formInfo from '@ohos.application.formInfo' + import formProvider from '@ohos.application.formProvider' + ``` + +2. Implement lifecycle callbacks for the widget. + + ```javascript + export default { + onCreate(want) { + console.log('FormAbility onCreate'); + // Persistently store widget information for subsequent use, such as widget instance retrieval or update. + let obj = { + "title": "titleOnCreate", + "detail": "detailOnCreate" + }; + let formData = formBindingData.createFormBindingData(obj); + return formData; + }, + onCastToNormal(formId) { + // Called when the widget host converts the temporary widget into a normal one. The widget provider should do something to respond to the conversion. + console.log('FormAbility onCastToNormal'); + }, + onUpdate(formId) { + // Override this method to support scheduled updates, periodic updates, or updates requested by the widget host. + console.log('FormAbility onUpdate'); + let obj = { + "title": "titleOnUpdate", + "detail": "detailOnUpdate" + }; + let formData = formBindingData.createFormBindingData(obj); + formProvider.updateForm(formId, formData).catch((error) => { + console.log('FormAbility updateForm, error:' + JSON.stringify(error)); + }); + }, + onVisibilityChange(newStatus) { + // Called when the widget host initiates an event about visibility changes. The widget provider should do something to respond to the notification. + console.log('FormAbility onVisibilityChange'); + }, + onEvent(formId, message) { + // If the widget supports event triggering, override this method and implement the trigger. + console.log('FormAbility onEvent'); + }, + onDestroy(formId) { + // Delete widget data. + console.log('FormAbility onDestroy'); + }, + onAcquireFormState(want) { + console.log('FormAbility onAcquireFormState'); + return formInfo.FormState.READY; + }, + } + ``` + +### Configuring the Widget Configuration File + +The widget configuration file is named **config.json**. Find the **config.json** file for the widget and edit the file depending on your need. + +- The **js** module in the **config.json** file provides JavaScript resources of the widget. The internal structure is described as follows: + + | Field| Description | Data Type| Default | + | -------- | ------------------------------------------------------------ | -------- | ------------------------ | + | name | Name of a JavaScript component. The default value is **default**. | String | No | + | pages | Route information about all pages in the JavaScript component, including the page path and page name. The value is an array, in which each element represents a page. The first element in the array represents the home page of the JavaScript FA.| Array | No | + | window | Window-related configurations. | Object | Yes | + | type | Type of the JavaScript component.
**normal**: indicates an application instance.
**form**: indicates a widget instance.| String | Yes (initial value: **normal**)| + | mode | Development mode of the JavaScript component. | Object | Yes (initial value: left empty) | + + Example configuration: + + ```json + "js": [{ + "name": "widget", + "pages": ["pages/index/index"], + "window": { + "designWidth": 720, + "autoDesignWidth": true + }, + "type": "form" + }] + ``` + +- The **abilities** module in the **config.json** file corresponds to **LifecycleForm** of the widget. The internal structure is described as follows: + + | Field | Description | Data Type | Default | + | ------------------- | ------------------------------------------------------------ | ---------- | ------------------------ | + | name | Class name of the widget. The value is a string with a maximum of 127 bytes. | String | No | + | description | Description of the widget. The value can be a string or a resource index to descriptions in multiple languages. The value is a string with a maximum of 255 bytes.| String | Yes (initial value: left empty) | + | isDefault | Whether the widget is a default one. Each ability has only one default widget.
**true**: The widget is the default one.
**false**: The widget is not the default one.| Boolean | No | + | type | Type of the widget.
**JS**: indicates a JavaScript-programmed widget. | String | No | + | colorMode | Color mode of the widget.
**auto**: The widget adopts the auto-adaptive color mode.
**dark**: The widget adopts the dark color mode.
**light**: The widget adopts the light color mode.| String | Yes (initial value: **auto**)| + | supportDimensions | Grid styles supported by the widget.
**1 * 2**: indicates a grid with one row and two columns.
**2 * 2**: indicates a grid with two rows and two columns.
**2 * 4**: indicates a grid with two rows and four columns.
**4 * 4**: indicates a grid with four rows and four columns.| String array| No | + | defaultDimension | Default grid style of the widget. The value must be available in the **supportDimensions** array of the widget.| String | No | + | updateEnabled | Whether the widget can be updated periodically.
**true**: The widget can be updated at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** takes precedence over **scheduledUpdateTime**.
**false**: The widget cannot be updated periodically.| Boolean | No | + | scheduledUpdateTime | Scheduled time to update the widget. The value is in 24-hour format and accurate to minute.
**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| String | Yes (initial value: **0:0**) | + | updateDuration | Interval to update the widget. The value is a natural number, in the unit of 30 minutes.
If the value is **0**, this field does not take effect.
If the value is a positive integer ***N***, the interval is calculated by multiplying ***N*** and 30 minutes.
**updateDuration** takes precedence over **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| Number | Yes (initial value: **0**) | + | formConfigAbility | Link to a specific page of the application. The value is a URI. | String | Yes (initial value: left empty) | + | formVisibleNotify | Whether the widget is allowed to use the widget visibility notification. | String | Yes (initial value: left empty) | + | jsComponentName | Component name of the widget. The value is a string with a maximum of 127 bytes. | String | No | + | metaData | Metadata of the widget. This field contains the array of the **customizeData** field. | Object | Yes (initial value: left empty) | + | customizeData | Custom information about the widget. | Object array | Yes (initial value: left empty) | + + Example configuration: + + ```json + "abilities": [{ + "name": "FormAbility", + "description": "This is a FormAbility", + "formsEnabled": true, + "icon": "$media:icon", + "label": "$string:form_FormAbility_label", + "srcPath": "FormAbility", + "type": "service", + "srcLanguage": "ets", + "formsEnabled": true, + "forms": [{ + "colorMode": "auto", + "defaultDimension": "2*2", + "description": "This is a widget.", + "formVisibleNotify": true, + "isDefault": true, + "jsComponentName": "widget", + "name": "widget", + "scheduledUpdateTime": "10:30", + "supportDimensions": ["2*2"], + "type": "JS", + "updateEnabled": true + }] + }] + ``` + + +### Persistently Storing Widget Data + +A widget provider is usually started when it is needed to provide information about a widget. The Widget Manager supports multi-instance management and uses the widget ID to identify an instance. If the widget provider supports widget data modification, it must persistently store the data based on the widget ID, so that it can access the data of the target widget when obtaining, updating, or starting a widget. + +```javascript + onCreate(want) { + console.log('FormAbility onCreate'); + + let formId = want.parameters["ohos.extra.param.key.form_identity"]; + let formName = want.parameters["ohos.extra.param.key.form_name"]; + let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"]; + // Persistently store widget information for subsequent use, such as widget instance retrieval or update. + // The storeFormInfo API is not implemented here. + storeFormInfo(formId, formName, tempFlag, want); + + let obj = { + "title": "titleOnCreate", + "detail": "detailOnCreate" + }; + let formData = formBindingData.createFormBindingData(obj); + return formData; + } +``` + +You should override **onDestroy** to implement widget data deletion. + +```javascript + onDestroy(formId) { + console.log('FormAbility onDestroy'); + + // You need to implement the code for deleting the persistent widget data. + // The deleteFormInfo API is not implemented here. + deleteFormInfo(formId); + } +``` + +For details about how to implement persistence data storage, see [Lightweight Data Store Development](../database/database-preference-guidelines.md). + +The **Want** passed by the widget host to the widget provider contains a flag that specifies whether the requested widget is normal or temporary. + +- Normal widget: a widget persistently used by the widget host + +- Temporary widget: a widget temporarily used by the widget host + +Data 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. + +### Updating Widget Data + +When an application initiates a scheduled or periodic update, the application obtains the latest data and calls **updateForm** to update the widget. The code snippet is as follows: + +```javascript +onUpdate(formId) { + // Override this method to support scheduled updates, periodic updates, or updates requested by the widget host. + console.log('FormAbility onUpdate'); + let obj = { + "title": "titleOnUpdate", + "detail": "detailOnUpdate" + }; + let formData = formBindingData.createFormBindingData(obj); + // Call the updateForm method to update the widget. Only the data passed through the input parameter is updated. Other information remains unchanged. + formProvider.updateForm(formId, formData).catch((error) => { + console.log('FormAbility updateForm, error:' + JSON.stringify(error)); + }); +} +``` + +### Developing Widget UI Pages + +You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programmed widget. + +> **NOTE** +> +> Only the JavaScript-based web-like development paradigm is supported when developing the widget UI. + + - HML file: + ```html +
+ +
+ +
+
+ {{title}} + {{detail}} +
+
+
+ ``` + + - CSS file: + + ```css +.container { + flex-direction: column; + justify-content: center; + align-items: center; +} + +.bg-img { + flex-shrink: 0; + height: 100%; +} + +.container-inner { + flex-direction: column; + justify-content: flex-end; + align-items: flex-start; + height: 100%; + width: 100%; + padding: 12px; +} + +.title { + font-size: 19px; + font-weight: bold; + color: white; + text-overflow: ellipsis; + max-lines: 1; +} + +.detail_text { + font-size: 16px; + color: white; + opacity: 0.66; + text-overflow: ellipsis; + max-lines: 1; + margin-top: 6px; +} + ``` + + - JSON file: + ```json + { + "data": { + "title": "TitleDefault", + "detail": "TextDefault" + }, + "actions": { + "routerEvent": { + "action": "router", + "abilityName": "com.example.entry.MainAbility", + "params": { + "message": "add detail" + } + } + } + } + ``` + +Now you've got a widget shown below. + +![fa-form-example](figures/fa-form-example.png) + +### Developing Widget Events + +You can set router and message events for components on a widget. The router event applies to ability redirection, and the message event applies to custom click events. The key steps are as follows: + +1. Set the **onclick** field in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file. +2. For the router event, set the following attributes: + - **action**: **router**, which indicates a router event. + - **abilityName**: target ability name, for example, **com.example.entry.MainAbility**, which is the default main ability name in DevEco Studio for the FA model. + - **params**: custom parameters of the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the main ability in the FA model, **featureAbility.getWant()** can be used to obtain **want** and its **parameters** field. +3. For the message event, set the following attributes: + - **action**: **message**, which indicates a message event. + - **params**: custom parameters of the message event. Set them as required. The value can be obtained from **message** in the widget lifecycle function **onEvent**. + +The code snippet is as follows: + + - HML file: + ```html +
+ +
+ +
+
+ {{title}} + {{detail}} +
+
+
+ ``` + + - JSON file: + ```json + { + "data": { + "title": "TitleDefault", + "detail": "TextDefault" + }, + "actions": { + "routerEvent": { + "action": "router", + "abilityName": "com.example.entry.MainAbility", + "params": { + "message": "add detail" + } + }, + "messageEvent": { + "action": "message", + "params": { + "message": "add detail" + } + } + } + } + ``` \ No newline at end of file diff --git a/en/application-dev/ability-deprecated/fa-pageability.md b/en/application-dev/ability-deprecated/fa-pageability.md new file mode 100644 index 0000000000000000000000000000000000000000..2f4741b80ef771c9b478d32a7713b597fb65c2d4 --- /dev/null +++ b/en/application-dev/ability-deprecated/fa-pageability.md @@ -0,0 +1,224 @@ +# Page Ability Development + +## Overview + +### Concepts + +The Page ability implements the ArkUI and provides the capability of interacting with developers. When you create an ability in DevEco Studio, DevEco Studio automatically creates template code. + +The capabilities related to the Page ability are implemented through the **featureAbility**, and the lifecycle callbacks are implemented through the callbacks in **app.js** or **app.ets**. + +### Page Ability Lifecycle + +Introduction to the Page ability lifecycle: + +The Page ability lifecycle defines all states of a Page ability, such as **INACTIVE**, **ACTIVE**, and **BACKGROUND**. + +The following figure shows the lifecycle state transition of the Page ability. + +![PageAbility-Lifecycle](figures/page-ability-lifecycle.png) + + +Description of ability lifecycle states: + + - **UNINITIALIZED**: The Page ability is not initialized. This is a temporary state, from which a Page ability changes directly to the **INITIAL** state upon its creation. + + - **INITIAL**: The Page ability is initialized but not running. The Page ability enters the **INACTIVE** state after it is started. + + - **INACTIVE**: The Page ability is visible but does not gain focus. + + - **ACTIVE**: The Page ability runs in the foreground and has focus. + + - **BACKGROUND**: The Page ability runs in the background. After being re-activated, the Page ability enters the **ACTIVE** state. After being destroyed, the Page ability enters the **INITIAL** state. + +The following figure shows the relationship between lifecycle callbacks and lifecycle states of the Page ability. + +![fa-pageAbility-lifecycle](figures/fa-pageAbility-lifecycle.png) + +You can override the lifecycle callbacks provided by the Page ability in the **app.js** or **app.ets** file. Currently, the **app.js** file provides only the **onCreate** and **onDestroy** callbacks, and the **app.ets** file provides the full lifecycle callbacks. + +### Launch Type + +The ability supports two launch types: singleton and multi-instance. + +You can specify the launch type by setting **launchType** in the **config.json** file. + +**Table 1** Startup modes + +| Launch Type | Description |Description | +| ----------- | ------- |---------------- | +| standard | Multi-instance | A new instance is started each time an ability starts.| +| singleton | Singleton | The ability has only one instance in the system. If an instance already exists when an ability is started, that instance is reused.| + +By default, **singleton** is used. + + +## Development Guidelines + +### Available APIs + +**Table 2** APIs provided by featureAbility + +| API | Description | +| --------------------------------------------------- | --------------- | +| void startAbility(parameter: StartAbilityParameter) | Starts an ability. | +| Context getContext(): | Obtains the application context.| +| void terminateSelf() | Terminates the ability. | +| bool hasWindowFocus() | Checks whether the ability has focus. | + + +### Starting a Local Page Ability + +**Modules to Import** + +```js + import featureAbility from '@ohos.ability.featureAbility' +``` + +**Example** + +```javascript + import featureAbility from '@ohos.ability.featureAbility' + featureAbility.startAbility({ + want: { + action: "", + entities: [""], + type: "", + deviceId: "", + bundleName: "com.example.myapplication", + /* In the FA model, abilityName consists of package and ability name. */ + abilityName: "com.example.entry.secondAbility", + uri: "" + } + }); +``` + +### Starting a Remote Page Ability +>NOTE +> +>This feature applies only to system applications, since the **getTrustedDeviceListSync** API of the **DeviceManager** class is open only to system applications. + +**Modules to Import** + +``` + import featureAbility from '@ohos.ability.featureAbility' + import deviceManager from '@ohos.distributedHardware.deviceManager'; +``` + +**Example** +```ts + function onStartRemoteAbility() { + console.info('onStartRemoteAbility begin'); + let params; + let wantValue = { + bundleName: 'ohos.samples.etsDemo', + abilityName: 'ohos.samples.etsDemo.RemoteAbility', + deviceId: getRemoteDeviceId(), + parameters: params + }; + console.info('onStartRemoteAbility want=' + JSON.stringify(wantValue)); + featureAbility.startAbility({ + want: wantValue + }).then((data) => { + console.info('onStartRemoteAbility finished, ' + JSON.stringify(data)); + }); + console.info('onStartRemoteAbility end'); + } +``` + +Obtain **deviceId** from **DeviceManager**. The sample code is as follows: + +```ts + import deviceManager from '@ohos.distributedHardware.deviceManager'; + let dmClass; + function getRemoteDeviceId() { + if (typeof dmClass === 'object' && dmClass != null) { + let list = dmClass.getTrustedDeviceListSync(); + if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { + console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null"); + return; + } + console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId); + return list[0].deviceId; + } else { + console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null"); + } + } +``` + +In the cross-device scenario, the application must also apply for the data synchronization permission from end users. The sample code is as follows: + +```ts + import abilityAccessCtrl from "@ohos.abilityAccessCtrl"; + import bundle from '@ohos.bundle'; + async function RequestPermission() { + console.info('RequestPermission begin'); + let array: Array = ["ohos.permission.DISTRIBUTED_DATASYNC"]; + let bundleFlag = 0; + let tokenID = undefined; + let userID = 100; + let appInfo = await bundle.getApplicationInfo('ohos.samples.etsDemo', bundleFlag, userID); + tokenID = appInfo.accessTokenId; + let atManager = abilityAccessCtrl.createAtManager(); + let requestPermissions: Array = []; + for (let i = 0;i < array.length; i++) { + let result = await atManager.verifyAccessToken(tokenID, array[i]); + console.info("verifyAccessToken result:" + JSON.stringify(result)); + if (result != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { + requestPermissions.push(array[i]); + } + } + console.info("requestPermissions:" + JSON.stringify(requestPermissions)); + if (requestPermissions.length == 0 || requestPermissions == []) { + return; + } + let context = featureAbility.getContext(); + context.requestPermissionsFromUser(requestPermissions, 1, (data)=>{ + console.info("data:" + JSON.stringify(data)); + console.info("data requestCode:" + data.requestCode); + console.info("data permissions:" + data.permissions); + console.info("data authResults:" + data.authResults); + }); + console.info('RequestPermission end'); + } +``` + +### Lifecycle APIs + +**Table 3** Lifecycle callbacks + +| API | Description | +| ------------ | ------------------------------------------------------------ | +| onShow() | Called when the ability is switched from the background to the foreground. In this case, the ability is visible to users.| +| onHide() | Called when the ability is switched from the foreground to the background. In this case, the ability is invisible to users.| +| onDestroy() | Called when the ability is destroyed. In this callback, you can make preparations for application exit, such as recycling resources and clearing the cache.| +| onCreate() | Called when the ability is created for the first time. You can initialize the application in this callback.| +| onInactive() | Called when the ability loses focus. An ability loses focus when it is about to enter the background state.| +| onActive() | Called when the ability is switched to the foreground and gains focus. | + +**Example** + +You need to override the lifecycle callbacks except **onCreate()** and **onDestroy()** in **app.js** or **app.ets**. The **onCreate()** and **onDestroy()** callbacks are automatically generated in the template code provided by DevEco Studio. + +```javascript +export default { + onCreate() { + console.info('Application onCreate') + }, + onDestroy() { + console.info('Application onDestroy') + }, + onShow(){ + console.info('Application onShow') + }, + onHide(){ + console.info('Application onHide') + }, + onInactive(){ + console.info('Application onInactive') + }, + onActive(){ + console.info('Application onActive') + }, +} +``` diff --git a/en/application-dev/ability-deprecated/fa-serviceability.md b/en/application-dev/ability-deprecated/fa-serviceability.md new file mode 100644 index 0000000000000000000000000000000000000000..cf766f35f72c76eb738d3b168d39cbcba0f21da3 --- /dev/null +++ b/en/application-dev/ability-deprecated/fa-serviceability.md @@ -0,0 +1,335 @@ +# Service Ability Development + +## When to Use +A Service ability is used to run tasks in the background, such as playing music or downloading files. It does not provide a UI for user interaction. Service abilities can be started by other applications or abilities and can keep running in the background even after the user switches to another application. + +## Lifecycle APIs + +**Table 1** Service ability lifecycle APIs +|API|Description| +|:------|:------| +|onStart?(): void|Called to initialize a Service ability when the Service ability is being created. This callback is invoked only once in the entire lifecycle of a Service ability.| +|onCommand?(want: Want, startId: number): void|Called every time a Service ability is created on the client. You can collect calling statistics and perform initialization operations in this callback.| +|onConnect?(want: Want): rpc.RemoteObject|Called when another ability is connected to the Service ability.| +|onDisconnect?(want: Want): void|Called when another ability is disconnected from the Service ability.| +|onStop?(): void|Called when the Service ability is being destroyed. You should override this callback for your Service ability to clear its resources, such as threads and registered listeners.| + +The differences between **onCommand()** and **onConnect()** are as follows: + - The **onCommand()** callback is triggered each time the client starts the Service ability by calling **startAbility** or **startAbilityForResult**. + - The **onConnect()** callback is triggered each time the client establishes a new connection with the Service ability by calling **connectAbility**. + +## How to Develop + +### Creating and Registering a Service Ability + +1. Override the Service ability-related lifecycle callbacks to implement your own logic for processing interaction requests. + + + + ```ts + export default { + onStart() { + console.log('ServiceAbility onStart'); + }, + onCommand(want, startId) { + console.log('ServiceAbility onCommand'); + }, + onConnect(want) { + console.log('ServiceAbility OnConnect'); + // Below lists the implementation of ServiceAbilityStub. + return new ServiceAbilityStub('test'); + }, + onDisconnect(want) { + console.log('ServiceAbility OnDisConnect'); + }, + onStop() { + console.log('ServiceAbility onStop'); + } + } + ``` + +2. Register a Service ability. + + Declare the Service ability in the **config.json** file by setting its **type** attribute to **service**. + + ```json + { + "module": { + "abilities": [ + { + "name": ".ServiceAbility", + "type": "service", + "visible": true + ... + } + ] + ... + } + ... + } + ``` + + + +### Starting a Service Ability + +The **Ability** class provides the **startAbility()** API for you to start another Service ability by passing a **Want** object. + +To set information about the target Service ability, you can first construct a **Want** object with the **bundleName** and **abilityName** parameters specified. + +- **bundleName** specifies the bundle name of the target application. +- **abilityName** specifies the target ability name. + +The following code snippet shows how to start a Service ability running on the local device: + +```ts +import featureAbility from '@ohos.ability.featureAbility' + +featureAbility.startAbility( + { + want: + { + bundleName: "com.jstest.service", + abilityName: "com.jstest.service.ServiceAbility" + } + } +).then((err) => { + console.log("startService success"); +}).catch (err => { + console.log("startService FAILED"); +}); +``` + +In the preceding code, the **startAbility()** API is used to start the Service ability. +- If the Service ability is not running, the system initializes the Service ability, and calls **onStart()** and **onCommand()** on the Service ability in sequence. +- If the Service ability is running, the system directly calls **onCommand()** on the Service ability. + +The following code snippet shows how to start a Service ability running on the remote device. For details, see [Connecting to a Remote Service Ability](#connecting-to-a-remote-service-ability). + +```ts +import featureAbility from '@ohos.ability.featureAbility' + +featureAbility.startAbility( + { + want: + { + deviceId: remoteDeviceId, // Remote device ID. + bundleName: "com.jstest.service", + abilityName: "com.jstest.service.ServiceAbility" + } + } +).then((err) => { + console.log("startService success"); +}).catch (err => { + console.log("startService FAILED"); +}); +``` + + +### Stopping a Service Ability + + In normal cases, a Service ability can be stopped by itself or by the system. + - The Service ability can call **particleAbility.terminateSelf()** to stop itself. + - If the application process where the Service ability is located exits, the Service ability is reclaimed along with the process. + - If the Service ability is only accessed through **connectAbility()** (the **onCommand()** callback has never been triggered), the system stops the Service ability when the last connection to the Service ability is disconnected. + +### Connecting to a Local Service Ability + +If a Service ability wants to interact with a Page ability or a Service ability in another application, you must first create a connection. A Service ability allows other abilities to connect to it through **connectAbility()**. + + +You can use either of the following methods to connect to a Service ability: + +1. Using the IDL to automatically generate code + + Use OpenHarmony Interface Definition Language (IDL) to automatically generate the corresponding client, server, and **IRemoteObject** code. For details, see [Development Using TS](../IDL/idl-guidelines.md#development-using-ts). + +2. Writing code in the corresponding file + + When using **connectAbility()**, pass the **Want** and **ConnectOptions** objects of the target Service ability, where **ConnectOptions** encapsulates the following three callbacks that need to be implemented. + - **onConnect()**: callback used for processing when the Service ability is connected. + - **onDisconnect()**: callback used for processing when the Service ability is disconnected. + - **onFailed()**: callback used for processing when the connection to the Service ability fails. + + The following code snippet shows how to implement the callbacks: + + ```ts + import prompt from '@system.prompt' + + var option = { + onConnect: function onConnectCallback(element, proxy) { + console.log(`onConnectLocalService onConnectDone`); + if (proxy === null) { + prompt.showToast({ + message: "Connect service failed" + }); + return; + } + // After obtaining the proxy of the Service ability, the calling ability can communicate with the Service ability. + let data = rpc.MessageParcel.create(); + let reply = rpc.MessageParcel.create(); + let option = new rpc.MessageOption(); + data.writeString("InuptString"); + proxy.sendRequest(0, data, reply, option); + prompt.showToast({ + message: "Connect service success" + }); + }, + onDisconnect: function onDisconnectCallback(element) { + console.log(`onConnectLocalService onDisconnectDone element:${element}`); + prompt.showToast({ + message: "Disconnect service success" + }); + }, + onFailed: function onFailedCallback(code) { + console.log(`onConnectLocalService onFailed errCode:${code}`); + prompt.showToast({ + message: "Connect local service onFailed" + }); + } + }; + ``` + + The following code snippet shows how to connect to a local Service ability: + + ```ts + import featureAbility from '@ohos.ability.featureAbility' + + let want = { + bundleName: "com.jstest.service", + abilityName: "com.jstest.service.ServiceAbility" + }; + let connectId = featureAbility.connectAbility(want, option); + ``` + + When a Service ability is connected, the **onConnect()** callback is invoked and returns an **IRemoteObject** defining the proxy used for communicating with the Service ability. OpenHarmony provides the default implementation of **IRemoteObject**. You can inherit **rpc.RemoteObject** to create a custom implementation class for interaction with the Service ability. For details, see the [RPC API Reference](..\reference\apis\js-apis-rpc.md). + + The following code snippet shows how the Service ability returns itself to the calling ability: + + ```ts + import rpc from "@ohos.rpc" + + class ServiceAbilityStub extends rpc.RemoteObject { + constructor(des: any) { + if (typeof des === 'string') { + super(des); + } else { + console.log("Error, the input param is not string"); + return; + } + } + + onRemoteRequest(code: number, data: any, reply: any, option: any) { + console.log("onRemoteRequest called"); + // Execute the service logic. + if (code === 1) { + // Sort the input strings. + let string = data.readString(); + console.log(`Input string = ${string}`); + let result = Array.from(string).sort().join(''); + console.log(`Output result = ${result}`); + reply.writeString(result); + } else { + console.log(`Unknown request code`); + } + return true; + } + } + + export default { + onStart() { + console.log('ServiceAbility onStart'); + }, + onCommand(want, startId) { + console.log('ServiceAbility onCommand'); + }, + onConnect(want) { + console.log('ServiceAbility OnConnect'); + return new ServiceAbilityStub('ServiceAbilityRemoteObject'); + }, + onDisconnect(want) { + console.log('ServiceAbility OnDisConnect'); + }, + onStop() { + console.log('ServiceAbility onStop'); + } + } + ``` + +### Connecting to a Remote Service Ability + +This feature applies only to system applications. The method of creating a **ConnectOptions** object for connecting to a remote Service ability is similar to that for connecting to a local Service ability. The differences are as follows: + - The application must apply for the data synchronization permission from the user. + - **Want** of the target Service ability must contain the remote device ID. + +> **NOTE** +> +> The **getTrustedDeviceList** API of **DeviceManager** is open only to system applications. Currently, only system applications can connect to a remote Service ability. +> +> For details about the API definition, see [Device Management](..\reference\apis\js-apis-device-manager.md). + +The data synchronization permission is required in the cross-device scenario. Configure the permission in the **config.json** file. + +```json +{ + ... + "module": { + ... + "reqPermissions": [{ + "name": "ohos.permission.DISTRIBUTED_DATASYNC" + }] + } +} +``` + +The **DISTRIBUTED_DATASYNC** permission is user granted. Therefore, your application, when being started, must display a dialog box to request the permission. The sample code is as follows: + +```ts +import abilityAccessCtrl from "@ohos.abilityAccessCtrl" +import bundle from '@ohos.bundle' + +async function RequestPermission() { + console.info('RequestPermission begin'); + let array: Array = ["ohos.permission.DISTRIBUTED_DATASYNC"]; + let bundleFlag = 0; + let tokenID = undefined; + let userID = 100; + let appInfo = await bundle.getApplicationInfo('ohos.samples.etsDemo', bundleFlag, userID); + tokenID = appInfo.accessTokenId; + let atManager = abilityAccessCtrl.createAtManager(); + let requestPermissions: Array = []; + for (let i = 0;i < array.length; i++) { + let result = await atManager.verifyAccessToken(tokenID, array[i]); + console.info("verifyAccessToken result:" + JSON.stringify(result)); + if (result != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { + requestPermissions.push(array[i]); + } + } + console.info("requestPermissions:" + JSON.stringify(requestPermissions)); + if (requestPermissions.length == 0 || requestPermissions == []) { + return; + } + let context = featureAbility.getContext(); + context.requestPermissionsFromUser(requestPermissions, 1, (data)=>{ + console.info("data:" + JSON.stringify(data)); + }); + console.info('RequestPermission end'); +} +``` + +To obtain the device ID, import the **@ohos.distributedHardware.deviceManager** module, which provides **getTrustedDeviceList** to obtain the remote device ID. For details about how to use the API, see [Device Management](..\reference\apis\js-apis-device-manager.md). + +To connect to a remote Service ability, you only need to define **deviceId** in **Want**. The sample code is as follows: + +```ts +import featureAbility from '@ohos.ability.featureAbility' + +let want = { + deviceId: remoteDeviceId, + bundleName: "com.jstest.service", + abilityName: "com.jstest.service.ServiceAbility" +}; +let connectId = featureAbility.connectAbility(want, option); +``` + +The other implementations are the same as those for the connection to a local Service ability. For details, see the sample code provided under [Connecting to a Local Service Ability](#connecting-to-a-local-service-ability). diff --git a/en/application-dev/ability/figures/AbilityComponentInstanceMission.png b/en/application-dev/ability-deprecated/figures/AbilityComponentInstanceMission.png similarity index 100% rename from en/application-dev/ability/figures/AbilityComponentInstanceMission.png rename to en/application-dev/ability-deprecated/figures/AbilityComponentInstanceMission.png diff --git a/en/application-dev/ability/figures/ExtensionAbility.png b/en/application-dev/ability-deprecated/figures/ExtensionAbility.png similarity index 100% rename from en/application-dev/ability/figures/ExtensionAbility.png rename to en/application-dev/ability-deprecated/figures/ExtensionAbility.png diff --git a/en/application-dev/ability/figures/aa-dump-a.PNG b/en/application-dev/ability-deprecated/figures/aa-dump-a.PNG similarity index 100% rename from en/application-dev/ability/figures/aa-dump-a.PNG rename to en/application-dev/ability-deprecated/figures/aa-dump-a.PNG diff --git a/en/application-dev/ability/figures/aa-dump-i.PNG b/en/application-dev/ability-deprecated/figures/aa-dump-i.PNG similarity index 100% rename from en/application-dev/ability/figures/aa-dump-i.PNG rename to en/application-dev/ability-deprecated/figures/aa-dump-i.PNG diff --git a/en/application-dev/ability/figures/aa-dump-l.PNG b/en/application-dev/ability-deprecated/figures/aa-dump-l.PNG similarity index 100% rename from en/application-dev/ability/figures/aa-dump-l.PNG rename to en/application-dev/ability-deprecated/figures/aa-dump-l.PNG diff --git a/en/application-dev/ability-deprecated/figures/contextIntroduction.png b/en/application-dev/ability-deprecated/figures/contextIntroduction.png new file mode 100644 index 0000000000000000000000000000000000000000..50ec4d39f722431513051be8f6674f15307117f4 Binary files /dev/null and b/en/application-dev/ability-deprecated/figures/contextIntroduction.png differ diff --git a/en/application-dev/ability/figures/continuation-info.png b/en/application-dev/ability-deprecated/figures/continuation-info.png similarity index 100% rename from en/application-dev/ability/figures/continuation-info.png rename to en/application-dev/ability-deprecated/figures/continuation-info.png diff --git a/en/application-dev/ability/figures/continuationManager.png b/en/application-dev/ability-deprecated/figures/continuationManager.png similarity index 100% rename from en/application-dev/ability/figures/continuationManager.png rename to en/application-dev/ability-deprecated/figures/continuationManager.png diff --git a/en/application-dev/ability/figures/fa-dataability-uri.png b/en/application-dev/ability-deprecated/figures/fa-dataability-uri.png similarity index 100% rename from en/application-dev/ability/figures/fa-dataability-uri.png rename to en/application-dev/ability-deprecated/figures/fa-dataability-uri.png diff --git a/en/application-dev/ability/figures/fa-form-example.png b/en/application-dev/ability-deprecated/figures/fa-form-example.png similarity index 100% rename from en/application-dev/ability/figures/fa-form-example.png rename to en/application-dev/ability-deprecated/figures/fa-form-example.png diff --git a/en/application-dev/ability/figures/fa-pageAbility-lifecycle.png b/en/application-dev/ability-deprecated/figures/fa-pageAbility-lifecycle.png similarity index 100% rename from en/application-dev/ability/figures/fa-pageAbility-lifecycle.png rename to en/application-dev/ability-deprecated/figures/fa-pageAbility-lifecycle.png diff --git a/en/application-dev/ability/figures/fa-threading-model.png b/en/application-dev/ability-deprecated/figures/fa-threading-model.png similarity index 100% rename from en/application-dev/ability/figures/fa-threading-model.png rename to en/application-dev/ability-deprecated/figures/fa-threading-model.png diff --git a/en/application-dev/ability-deprecated/figures/favsstage.png b/en/application-dev/ability-deprecated/figures/favsstage.png new file mode 100644 index 0000000000000000000000000000000000000000..4e5980fc1df4634d4ea1ff23158e79d62637f8ba Binary files /dev/null and b/en/application-dev/ability-deprecated/figures/favsstage.png differ diff --git a/zh-cn/application-dev/ability/figures/lifecycle.png b/en/application-dev/ability-deprecated/figures/lifecycle.png similarity index 100% rename from zh-cn/application-dev/ability/figures/lifecycle.png rename to en/application-dev/ability-deprecated/figures/lifecycle.png diff --git a/en/application-dev/ability/figures/page-ability-lifecycle.png b/en/application-dev/ability-deprecated/figures/page-ability-lifecycle.png similarity index 100% rename from en/application-dev/ability/figures/page-ability-lifecycle.png rename to en/application-dev/ability-deprecated/figures/page-ability-lifecycle.png diff --git a/en/application-dev/ability/figures/stage-call.png b/en/application-dev/ability-deprecated/figures/stage-call.png similarity index 100% rename from en/application-dev/ability/figures/stage-call.png rename to en/application-dev/ability-deprecated/figures/stage-call.png diff --git a/zh-cn/application-dev/ability/figures/stageabilitylifecyclecallback.png b/en/application-dev/ability-deprecated/figures/stageabilitylifecyclecallback.png similarity index 100% rename from zh-cn/application-dev/ability/figures/stageabilitylifecyclecallback.png rename to en/application-dev/ability-deprecated/figures/stageabilitylifecyclecallback.png diff --git a/en/application-dev/ability/figures/stageconcept.png b/en/application-dev/ability-deprecated/figures/stageconcept.png similarity index 100% rename from en/application-dev/ability/figures/stageconcept.png rename to en/application-dev/ability-deprecated/figures/stageconcept.png diff --git a/en/application-dev/ability/figures/stagedesign.png b/en/application-dev/ability-deprecated/figures/stagedesign.png similarity index 100% rename from en/application-dev/ability/figures/stagedesign.png rename to en/application-dev/ability-deprecated/figures/stagedesign.png diff --git a/en/application-dev/ability/figures/stageprocessmodel.png b/en/application-dev/ability-deprecated/figures/stageprocessmodel.png similarity index 100% rename from en/application-dev/ability/figures/stageprocessmodel.png rename to en/application-dev/ability-deprecated/figures/stageprocessmodel.png diff --git a/en/application-dev/ability/public_sys-resources/icon-caution.gif b/en/application-dev/ability-deprecated/public_sys-resources/icon-caution.gif similarity index 100% rename from en/application-dev/ability/public_sys-resources/icon-caution.gif rename to en/application-dev/ability-deprecated/public_sys-resources/icon-caution.gif diff --git a/en/application-dev/ability/public_sys-resources/icon-danger.gif b/en/application-dev/ability-deprecated/public_sys-resources/icon-danger.gif similarity index 100% rename from en/application-dev/ability/public_sys-resources/icon-danger.gif rename to en/application-dev/ability-deprecated/public_sys-resources/icon-danger.gif diff --git a/en/application-dev/ability/public_sys-resources/icon-note.gif b/en/application-dev/ability-deprecated/public_sys-resources/icon-note.gif similarity index 100% rename from en/application-dev/ability/public_sys-resources/icon-note.gif rename to en/application-dev/ability-deprecated/public_sys-resources/icon-note.gif diff --git a/en/application-dev/ability/public_sys-resources/icon-notice.gif b/en/application-dev/ability-deprecated/public_sys-resources/icon-notice.gif similarity index 100% rename from en/application-dev/ability/public_sys-resources/icon-notice.gif rename to en/application-dev/ability-deprecated/public_sys-resources/icon-notice.gif diff --git a/en/application-dev/ability/public_sys-resources/icon-tip.gif b/en/application-dev/ability-deprecated/public_sys-resources/icon-tip.gif similarity index 100% rename from en/application-dev/ability/public_sys-resources/icon-tip.gif rename to en/application-dev/ability-deprecated/public_sys-resources/icon-tip.gif diff --git a/en/application-dev/ability/public_sys-resources/icon-warning.gif b/en/application-dev/ability-deprecated/public_sys-resources/icon-warning.gif similarity index 100% rename from en/application-dev/ability/public_sys-resources/icon-warning.gif rename to en/application-dev/ability-deprecated/public_sys-resources/icon-warning.gif diff --git a/en/application-dev/ability-deprecated/stage-ability-continuation.md b/en/application-dev/ability-deprecated/stage-ability-continuation.md new file mode 100644 index 0000000000000000000000000000000000000000..7a11716f18f2c8b866e1fd11722ae0e07a32d4ce --- /dev/null +++ b/en/application-dev/ability-deprecated/stage-ability-continuation.md @@ -0,0 +1,313 @@ +# Ability Continuation Development + +## When to Use + +Ability continuation is to continue the current mission of an application, including the UI component state variables and distributed objects, on another device. The UI component state variables are used to synchronize UI data, and the distributed objects are used to synchronize memory data. + +## Available APIs + +The following table lists the APIs used for ability continuation. For details about the APIs, see [Ability](../reference/apis/js-apis-application-ability.md). + +**Table 1** Ability continuation APIs + +|API| Description| +|:------ | :------| +| onContinue(wantParam : {[key: string]: any}): OnContinueResult | Called by the initiator to store the data required for continuation. The return value indicates whether the continuation request is accepted. The value **AGREE** means that the continuation request is accepted, **REJECT** means that the continuation request is rejected, and **MISMATCH** means a version mismatch.| +| onCreate(want: Want, param: AbilityConstant.LaunchParam): void; | Called by the target to restore the data and UI page in the multi-instance ability scenario.| +| onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void; | Called by the target to restore the data and UI page in the singleton ability scenario.| + + + +**Figure 1** Ability continuation development + +![continuation_dev](figures/continuation-info.png) + +In effect, ability continuation is a cross-device ability startup that carries data. When a continuation action is initiated, the system on device A calls back **onContinue()** of the application. You must implement storage of the current data in this API. Then, the system initiates a cross-device ability startup on device B and transmits the data to device B. The system on device B calls back **onCreate()** or **onNewWant()**. You must implement restoration of the transmitted data in this API. + +## How to Develop + +The code snippets provided below are all from [Sample](https://gitee.com/openharmony/ability_dmsfwk/tree/master/services/dtbschedmgr/test/samples/continuationManualTestSuite). + +### Application Continuation + +1. Modify the configuration file. + + - Configure the application to support ability continuation. + + Set the **continuable** field in the **module.json5** file to **true**. The default value is **false**. If this parameter is set to **false**, the application cannot be continued on another device. + + ```javascript + { + "module": { + "abilities": [ + { + "continuable": true + } + ] + } + } + ``` + + + + + - Configure the application startup type. + + If **launchType** is set to **standard** in the **module.json5** file, the application is of the multi-instance launch type. During ability continuation, regardless of whether the application is already open, the target starts the application and restores the UI page. If **launchType** is set to **singleton**, the application is of the singleton launch type. If the application is already open, the target clears the existing page stack and restores the UI page. For more information, see "Launch Type" in [Ability Development](./stage-ability.md). + + Configure a multi-instance application as follows: + + ```javascript + { + "module": { + "abilities": [ + { + "launchType": "standard" + } + ] + } + } + ``` + + Configure a singleton application as follows or retain the default settings of **launchType**: + + ```javascript + { + "module": { + "abilities": [ + { + "launchType": "singleton" + } + ] + } + } + ``` + + + + - Apply for the distributed permissions. + + Declare the **DISTRIBUTED_DATASYNC** permission in the **module.json5** file for the application. + + ```javascript + "requestPermissions": [ + { + "name": "ohos.permission.DISTRIBUTED_DATASYNC" + }, + ``` + + + + This permission must be granted by the user in a dialog box when the application is started for the first time. To enable the application to display a dialog box to ask for the permission, add the following code to **onWindowStageCreate** of the **Ability** class: + + ```javascript + requestPermissions = async () => { + let permissions: Array = [ + "ohos.permission.DISTRIBUTED_DATASYNC" + ]; + let needGrantPermission = false + let accessManger = accessControl.createAtManager() + Logger.info("app permission get bundle info") + let bundleInfo = await bundle.getApplicationInfo(BUNDLE_NAME, 0, 100) + Logger.info(`app permission query permission ${bundleInfo.accessTokenId.toString()}`) + for (const permission of permissions) { + Logger.info(`app permission query grant status ${permission}`) + try { + let grantStatus = await accessManger.verifyAccessToken(bundleInfo.accessTokenId, permission) + if (grantStatus === PERMISSION_REJECT) { + needGrantPermission = true + break; + } + } catch (err) { + Logger.error(`app permission query grant status error ${permission} ${JSON.stringify(err)}`) + needGrantPermission = true + break; + } + } + if (needGrantPermission) { + Logger.info("app permission needGrantPermission") + try { + await this.context.requestPermissionsFromUser(permissions) + } catch (err) { + Logger.error(`app permission ${JSON.stringify(err)}`) + } + } else { + Logger.info("app permission already granted") + } + } + ``` + + + + +2. Implement the **onContinue()** API. + + The **onContinue()** API is called by the initiator to save the UI component state variables and memory data and prepare for continuation. After the application completes the continuation preparation, the system must return either **OnContinueResult.AGREE(0)** to accept the continuation request or an error code to reject the request. If this API is not implemented, the system rejects the continuation request by default. + + Modules to import: + + ```javascript + import Ability from '@ohos.application.Ability'; + import AbilityConstant from '@ohos.application.AbilityConstant'; + ``` + + To implement ability continuation, you must implement this API and have the value **AGREE** returned. + + You can obtain the target device ID (identified by the key **targetDevice**) and the version number (identified by the key **version**) of the application installed on the target device from the **wantParam** parameter of this API. The version number can be used for compatibility check. If the current application version is incompatible with that on the target device, **OnContinueResult.MISMATCH** can be returned to reject the continuation request. + + Example + + ```javascript + onContinue(wantParam : {[key: string]: any}) { + Logger.info(`onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`) + let workInput = AppStorage.Get('ContinueWork'); + // Set the user input data into wantParam. + wantParam["work"] = workInput // set user input data into want params + Logger.info(`onContinue input = ${wantParam["input"]}`); + return AbilityConstant.OnContinueResult.AGREE + } + ``` + + + +3. Implement the continuation logic in the **onCreate()** or **onNewWant()** API. + + The **onCreate()** API is called by the target. When the ability is started on the target device, this API is called to instruct the application to synchronize the memory data and UI component state, and triggers page restoration after the synchronization is complete. If the continuation logic is not implemented, the ability will be started in common startup mode and the page cannot be restored. + + The target device determines whether the startup is **LaunchReason.CONTINUATION** based on **launchReason** in **onCreate()**. + + After data restore is complete, call **restoreWindowStage** to trigger page restoration. + + + + You can also use **want.parameters.version** in the **want** parameter to obtain the application version number of the initiator. + + Example + + ```javascript + import Ability from '@ohos.application.Ability'; + import distributedObject from '@ohos.data.distributedDataObject'; + + export default class MainAbility extends Ability { + storage : LocalStorag; + + onCreate(want, launchParam) { + Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`) + if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) { + // Obtain the user data from the want parameter. + let workInput = want.parameters.work + Logger.info(`work input ${workInput}`) + AppStorage.SetOrCreate('ContinueWork', workInput) + + this.storage = new LocalStorage(); + this.context.restoreWindowStage(this.storage); + } + } + } + ``` +For a singleton ability, use **onNewWant()** to achieve the same implementation. + + + +### Data Continuation + +Use distributed objects. + +Distributed objects allow cross-device data synchronization like local variables. For two devices that form a Super Device, when data in the distributed data object of an application is added, deleted, or modified on a device, the data for the same application is also updated on the other device. Both devices can listen for the data changes and online and offline states of the other. For details, see [Distributed Data Object Development](../database/database-distributedobject-guidelines.md). + +In the ability continuation scenario, the distributed data object is used to synchronize the memory data from the local device to the target device. + +- In **onContinue()**, the initiator saves the data to be migrated to the distributed object, calls the **save()** API to save the data and synchronize the data to the target device, sets the session ID, and sends the session ID to the target device through **wantParam**. + + ```javascript + import Ability from '@ohos.application.Ability'; + import distributedObject from '@ohos.data.distributedDataObject'; + + var g_object = distributedObject.createDistributedObject({data:undefined}); + + export default class MainAbility extends Ability { + sessionId : string; + + onContinue(wantParam : {[key: string]: any}) { + Logger.info(`onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`) + + if (g_object.__sessionId === undefined) { + this.sessionId = distributedObject.genSessionId() + Logger.info(`onContinue generate new sessionId`) + } + else { + this.sessionId = g_object.__sessionId; + } + + wantParam["session"] = this.sessionId + g_object.data = AppStorage.Get('ContinueStudy'); + Logger.info(`onContinue sessionId = ${this.sessionId}, name = ${g_object.data}`) + g_object.setSessionId(this.sessionId); + g_object.save(wantParam.targetDevice, (result, data)=>{ + Logger.info("save callback"); + Logger.info("save sessionId " + data.sessionId); + Logger.info("save version " + data.version); + Logger.info("save deviceId " + data.deviceId); + }); + ``` + + + +- The target device obtains the session ID from **onCreate()**, creates a distributed object, and associates the distributed object with the session ID. In this way, the distributed object can be synchronized. Before calling **restoreWindowStage**, ensure that all distributed objects required for continuation have been associated. + + ```javascript + import Ability from '@ohos.application.Ability'; + import distributedObject from '@ohos.data.distributedDataObject'; + + var g_object = distributedObject.createDistributedObject({data:undefined}); + + export default class MainAbility extends Ability { + storage : LocalStorag; + + + onCreate(want, launchParam) { + Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`) + if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) { + // Obtain the session ID of the distributed data object from the want parameter. + this.sessionId = want.parameters.session + Logger.info(`onCreate for continuation sessionId: ${this.sessionId}`) + + // Before fetching data from the remote device, reset g_object.data to undefined. + g_object.data = undefined; + // Set the session ID, so the target will fetch data from the remote device. + g_object.setSessionId(this.sessionId); + + AppStorage.SetOrCreate('ContinueStudy', g_object.data) + this.storage = new LocalStorage(); + this.context.restoreWindowStage(this.storage); + } + + } + } + ``` + + + +### More Information + +1. Timeout + + - If the application to be continued is not installed on the target device, the system checks whether the application can be installed on it and waits for a response for 4 seconds. If no response is received within 4 seconds, the caller receives a timeout error code, which means that the application cannot be installed on the target device. If the application can be installed, the system prompts the consumer to install the application on the target device. The consumer can initiate the continuation again after the installation. + - If the application to be continued has been installed on the target device, the system waits for a response to the continuation request for 20 seconds. If no response is received within 20 seconds, the caller receives a timeout error code, which means that the continuation fails. + +2. By default, the system supports page stack information migration, which means that the page stack of the initiator will be automatically migrated to the target device. No adaptation is required. + + + +### Restrictions + +1. The continuation must be performed between the same ability, which means the same bundle name, module name, and ability name. For details, see [Application Package Structure Configuration File](../quick-start/module-configuration-file.md). +2. Currently, the application can only implement the continuation capability. The continuation action must be initiated by the system. + + + +### Best Practice + +For better user experience, you are advised to use the **wantParam** parameter to transmit data smaller than 100 KB and use distributed objects to transmit data larger than 100 KB. + + \ No newline at end of file diff --git a/en/application-dev/ability-deprecated/stage-ability.md b/en/application-dev/ability-deprecated/stage-ability.md new file mode 100644 index 0000000000000000000000000000000000000000..97ba5cff5cc083563f1d0f78c7b499bff2cd2050 --- /dev/null +++ b/en/application-dev/ability-deprecated/stage-ability.md @@ -0,0 +1,325 @@ +# Ability Development +## When to Use +Ability development in the [stage model](stage-brief.md) is significantly different from that in the FA model. The stage model requires you to declare the application package structure in the **module.json5** and **app.json5** files during application development. For details about the configuration file, see [Application Package Structure Configuration File](../quick-start/application-package-structure-stage.md). To develop an ability based on the stage model, implement the following logic: +- Create an ability that supports screen viewing and human-machine interaction. You must implement the following scenarios: ability lifecycle callbacks, obtaining ability configuration, requesting permissions, and notifying environment changes. +- Start an ability. You need to implement ability startup on the same device, on a remote device, or with a specified UI page. +- Call abilities. For details, see [Call Development](stage-call.md). +- Connect to and disconnect from a Service Extension ability. For details, see [Service Extension Ability Development](stage-serviceextension.md). +- Continue the ability on another device. For details, see [Ability Continuation Development](stage-ability-continuation.md). + +### Launch Type +An ability can be launched in the **standard**, **singleton**, or **specified** mode, as configured by **launchType** in the **module.json5** file. Depending on the launch type, the action performed when the ability is started differs, as described below. + +| Launch Type | Description |Action | +| ----------- | ------- |---------------- | +| standard | Standard mode | A new instance is started each time an ability starts.| +| singleton | Singleton mode | The ability has only one instance in the system. If an instance already exists when an ability is started, that instance is reused.| +| specified | Instance-specific| The internal service of an ability determines whether to create multiple instances during running.| + +By default, the singleton mode is used. The following is an example of the **module.json5** file: +```json +{ + "module": { + "abilities": [ + { + "launchType": "singleton", + } + ] + } +} +``` +## Creating an Ability +### Available APIs +The table below describes the APIs provided by the **AbilityStage** class, which has the **context** attribute. For details about the APIs, see [AbilityStage](../reference/apis/js-apis-app-ability-abilityStage.md). + +**Table 1** AbilityStage APIs +|API|Description| +|:------|:------| +|onCreate(): void|Called when an ability stage is created.| +|onAcceptWant(want: Want): string|Called when a specified ability is started.| +|onConfigurationUpdated(config: Configuration): void|Called when the global configuration is updated.| + +The table below describes the APIs provided by the **Ability** class. For details about the APIs, see [Ability](../reference/apis/js-apis-application-ability.md). + +**Table 2** Ability APIs + +|API|Description| +|:------|:------| +|onCreate(want: Want, param: AbilityConstant.LaunchParam): void|Called when an ability is created.| +|onDestroy(): void|Called when the ability is destroyed.| +|onWindowStageCreate(windowStage: window.WindowStage): void|Called when a **WindowStage** is created for the ability. You can use the **window.WindowStage** APIs to implement operations such as page loading.| +|onWindowStageDestroy(): void|Called when the **WindowStage** is destroyed for the ability.| +|onForeground(): void|Called when the ability is switched to the foreground.| +|onBackground(): void|Called when the ability is switched to the background.| +|onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void|Called when the ability launch type is set to **singleton**.| +|onConfigurationUpdated(config: Configuration): void|Called when the configuration of the environment where the ability is running is updated.| +### Implementing AbilityStage and Ability Lifecycle Callbacks +To create Page abilities for an application in the stage model, you must implement the **AbilityStage** class and ability lifecycle callbacks, and use the **Window** class to set the pages. The sample code is as follows: +1. Import the **AbilityStage** module. + ``` + import AbilityStage from "@ohos.application.AbilityStage" + ``` +2. Implement the **AbilityStage** class. The default relative path generated by the APIs is **entry\src\main\ets\Application\AbilityStage.ts**. + ```ts + export default class MyAbilityStage extends AbilityStage { + onCreate() { + console.log("MyAbilityStage onCreate") + } + } + ``` +3. Import the **Ability** module. + ```js + import Ability from '@ohos.application.Ability' + ``` +4. Implement the lifecycle callbacks of the **Ability** class. The default relative path generated by the APIs is **entry\src\main\ets\MainAbility\MainAbility.ts**. + + In the **onWindowStageCreate(windowStage)** API, use **loadContent** to set the application page to be loaded. For details about how to use the **Window** APIs, see [Window Development](../windowmanager/application-window-stage.md). + ```ts + export default class MainAbility extends Ability { + onCreate(want, launchParam) { + console.log("MainAbility onCreate") + } + + onDestroy() { + console.log("MainAbility onDestroy") + } + + onWindowStageCreate(windowStage) { + console.log("MainAbility onWindowStageCreate") + + windowStage.loadContent("pages/index").then(() => { + console.log("MainAbility load content succeed") + }).catch((error) => { + console.error("MainAbility load content failed with error: " + JSON.stringify(error)) + }) + } + + onWindowStageDestroy() { + console.log("MainAbility onWindowStageDestroy") + } + + onForeground() { + console.log("MainAbility onForeground") + } + + onBackground() { + console.log("MainAbility onBackground") + } + } + ``` +### Obtaining AbilityStage and Ability Configurations +Both the **AbilityStage** and **Ability** classes have the **context** attribute. An application can obtain the context of an **Ability** instance through **this.context** to obtain the configuration details. + +The following example shows how an application obtains the bundle code directory, HAP file name, ability name, and system language through the **context** attribute in the **AbilityStage** class. The sample code is as follows: + +```ts +import AbilityStage from "@ohos.application.AbilityStage" +export default class MyAbilityStage extends AbilityStage { + onCreate() { + console.log("MyAbilityStage onCreate") + let context = this.context + console.log("MyAbilityStage bundleCodeDir" + context.bundleCodeDir) + + let currentHapModuleInfo = context.currentHapModuleInfo + console.log("MyAbilityStage hap module name" + currentHapModuleInfo.name) + console.log("MyAbilityStage hap module mainAbilityName" + currentHapModuleInfo.mainAbilityName) + + let config = this.context.config + console.log("MyAbilityStage config language" + config.language) + } +} +``` + +The following example shows how an application obtains the bundle code directory, HAP file name, ability name, and system language through the **context** attribute in the **Ability** class. The sample code is as follows: +```ts +import Ability from '@ohos.application.Ability' +export default class MainAbility extends Ability { + onCreate(want, launchParam) { + console.log("MainAbility onCreate") + let context = this.context + console.log("MainAbility bundleCodeDir" + context.bundleCodeDir) + + let abilityInfo = this.context.abilityInfo; + console.log("MainAbility ability bundleName" + abilityInfo.bundleName) + console.log("MainAbility ability name" + abilityInfo.name) + + let config = this.context.config + console.log("MainAbility config language" + config.language) + } +} +``` +### Requesting Permissions +If an application needs to obtain user privacy information or use system capabilities, for example, obtaining location information or using the camera to take photos or record videos, it must request the respective permission from consumers. During application development, you need to specify the involved sensitive permissions, declare the required permissions in **module.json5**, and use the **requestPermissionsFromUser** API to request the permission from consumers in the form of a dialog box. The following uses the permission for calendar access as an example. + +Declare the required permission in the **module.json5** file. +```json +"requestPermissions": [ + { + "name": "ohos.permission.READ_CALENDAR" + } +] +``` +Request the permission from consumers in the form of a dialog box: +```ts +let context = this.context +let permissions: Array = ['ohos.permission.READ_CALENDAR'] +context.requestPermissionsFromUser(permissions).then((data) => { + console.log("Succeed to request permission from user with data: " + JSON.stringify(data)) +}).catch((error) => { + console.log("Failed to request permission from user with error: " + JSON.stringify(error)) +}) +``` +### Notifying of Environment Changes +Environment changes include changes of global configurations and ability configurations. Currently, the global configurations include the system language and color mode. The change of global configurations is generally triggered by configuration items in **Settings** or icons in **Control Panel**. The ability configuration is specific to a single **Ability** instance, including the display ID, screen resolution, and screen orientation. The configuration is related to the display where the ability is located, and the change is generally triggered by the window. For details on the configuration, see [Configuration](../reference/apis/js-apis-configuration.md). + +For an application in the stage model, when the configuration changes, its abilities are not restarted, but the **onConfigurationUpdated(config: Configuration)** callback is triggered. If the application needs to perform processing based on the change, you can overwrite **onConfigurationUpdated**. Note that the **Configuration** object in the callback contains all the configurations of the current ability, not only the changed configurations. + +The following example shows the implementation of the **onConfigurationUpdated** callback in the **AbilityStage** class. The callback is triggered when the system language and color mode are changed. +```ts +import AbilityStage from '@ohos.application.AbilityStage' +import ConfigurationConstant from '@ohos.application.ConfigurationConstant' + +export default class MyAbilityStage extends AbilityStage { + onConfigurationUpdated(config) { + if (config.colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) { + console.log('colorMode changed to dark') + } + } +} +``` + +The following example shows the implementation of the **onConfigurationUpdated** callback in the **Ability** class. The callback is triggered when the system language, color mode, or display parameters (such as the direction and density) change. +```ts +import Ability from '@ohos.application.Ability' +import ConfigurationConstant from '@ohos.application.ConfigurationConstant' + +export default class MainAbility extends Ability { + direction : number; + + onCreate(want, launchParam) { + this.direction = this.context.config.direction + } + + onConfigurationUpdated(config) { + if (this.direction !== config.direction) { + console.log(`direction changed to ${config.direction}`) + } + } +} +``` +## Starting an Ability +### Available APIs +The **Ability** class has the **context** attribute, which belongs to the **AbilityContext** class. The **AbilityContext** class has the **abilityInfo**, **currentHapModuleInfo**, and other attributes as well as the APIs used for starting abilities. For details, see [AbilityContext](../reference/apis/js-apis-ability-context.md). + +**Table 3** AbilityContext APIs +|API|Description| +|:------|:------| +|startAbility(want: Want, callback: AsyncCallback\): void|Starts an ability.| +|startAbility(want: Want, options?: StartOptions): Promise\|Starts an ability.| +|startAbilityWithAccount(want: Want, accountId: number, callback: AsyncCallback\): void|Starts an ability with the account ID.| +|startAbilityWithAccount(want: Want, accountId: number, options?: StartOptions): Promise\|Starts an ability with the account ID.| +|startAbilityForResult(want: Want, callback: AsyncCallback\): void|Starts an ability with the returned result.| +|startAbilityForResult(want: Want, options?: StartOptions): Promise\|Starts an ability with the returned result.| +|startAbilityForResultWithAccount(want: Want, accountId: number, callback: AsyncCallback\): void|Starts an ability with the execution result and account ID.| +|startAbilityForResultWithAccount(want: Want, accountId: number, options?: StartOptions): Promise\|Starts an ability with the execution result and account ID.| +### Starting an Ability on the Same Device +An application can obtain the context of an **Ability** instance through **this.context** and then use the **startAbility** API in the **AbilityContext** class to start the ability. The ability can be started by specifying **Want**, **StartOptions**, and **accountId**, and the operation result can be returned using a callback or **Promise** instance. The sample code is as follows: +```ts +let context = this.context +var want = { + "deviceId": "", + "bundleName": "com.example.MyApplication", + "abilityName": "MainAbility" +}; +context.startAbility(want).then(() => { + console.log("Succeed to start ability") +}).catch((error) => { + console.error("Failed to start ability with error: "+ JSON.stringify(error)) +}) +``` + +### Starting an Ability on a Remote Device +>This feature applies only to system applications, since the **getTrustedDeviceListSync** API of the **DeviceManager** class is open only to system applications. +In the cross-device scenario, you must specify the ID of the remote device. The sample code is as follows: +```ts +let context = this.context +var want = { + "deviceId": getRemoteDeviceId(), + "bundleName": "com.example.MyApplication", + "abilityName": "MainAbility" +}; +context.startAbility(want).then(() => { + console.log("Succeed to start remote ability") +}).catch((error) => { + console.error("Failed to start remote ability with error: " + JSON.stringify(error)) +}) +``` +Obtain the ID of a specified device from **DeviceManager**. The sample code is as follows: +```ts +import deviceManager from '@ohos.distributedHardware.deviceManager'; +function getRemoteDeviceId() { + if (typeof dmClass === 'object' && dmClass != null) { + var list = dmClass.getTrustedDeviceListSync(); + if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { + console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null"); + return; + } + console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId); + return list[0].deviceId; + } else { + console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null"); + } +} +``` +Request the permission **ohos.permission.DISTRIBUTED_DATASYNC** from consumers. This permission is used for data synchronization. For details about the sample code for requesting the permission, see [Requesting Permissions](#requesting-permissions). +### Starting an Ability with the Specified Page +If the launch type of an ability is set to **singleton** and the ability has been started, the **onNewWant** callback is triggered when the ability is started again. You can pass start options through the **want**. For example, to start an ability with the specified page, use the **uri** or **parameters** parameter in the **want** to pass the page information. Currently, the ability in the stage model cannot directly use the **router** capability. You must pass the start options to the custom component and invoke the **router** method to display the specified page during the custom component lifecycle management. The sample code is as follows: + +When using **startAbility** to start an ability again, use the **uri** parameter in the **want** to pass the page information. +```ts +async function reStartAbility() { + try { + await this.context.startAbility({ + bundleName: "com.sample.MyApplication", + abilityName: "MainAbility", + uri: "pages/second" + }) + console.log('start ability succeed') + } catch (error) { + console.error(`start ability failed with ${error.code}`) + } +} +``` + +Obtain the **want** parameter that contains the page information from the **onNewWant** callback of the ability. +```ts +import Ability from '@ohos.application.Ability' + +export default class MainAbility extends Ability { + onNewWant(want, launchParams) { + globalThis.newWant = want + } +} +``` + +Obtain the **want** parameter that contains the page information from the custom component and process the route based on the URI. +```ts +import router from '@ohos.router' + +@Entry +@Component +struct Index { + newWant = undefined + + onPageShow() { + console.info('Index onPageShow') + let newWant = globalThis.newWant + if (newWant.hasOwnProperty("uri")) { + router.push({ url: newWant.uri }); + globalThis.newWant = undefined + } + } +} +``` + + \ No newline at end of file diff --git a/en/application-dev/ability-deprecated/stage-brief.md b/en/application-dev/ability-deprecated/stage-brief.md new file mode 100644 index 0000000000000000000000000000000000000000..2d5474e2c2f0e8328add287481b5ea47abcb2725 --- /dev/null +++ b/en/application-dev/ability-deprecated/stage-brief.md @@ -0,0 +1,114 @@ +# Stage Model Overview + +## Design Ideas + +The stage model is designed to provide a better application development mode in the distributed environment. + +The following figure shows the design ideas of the stage model. + +![stagedesign](figures/stagedesign.png) + +The stage model is designed based on the following considerations: + +- Efficient management of application processes + +As the device memory becomes larger, the number of processes concurrently running in the system increases. If the number of concurrent processes reaches several hundreds, the overall power consumption and performance of the system will be adversely affected without effective management measures. To restrict the behavior of background processes, the stage model uses four measures: transient task, continuous task, agent task, and Work Scheduler task. With these measures, foreground processes will obtain guaranteed resources, thereby delivering a better user experience. + +- Native support for cross-device migration and multi-device collaboration + +OpenHarmony is a native distributed OS. Its application framework must be designed for easier component migration and collaboration across devices. The stage model achieves this design objective by providing features such as separation between ability and UI as well as integration of UI display and service capabilities. + +- Different window forms for various device types + +The stage model redefines the ability lifecycle. In terms of architecture, the component manager and window manager are decoupled. This facilitates adaptation between window forms and device types. + +## Basic Concepts + +The following figure shows the basic concepts in the stage model. + +![stageconcept](figures/stageconcept.png) + +- **HAP**: basic unit for building, distributing, and loading OpenHarmony applications. Each HAP corresponds to a module in the development state. In an application, **moduleName** uniquely identifies a module. +- **Bundle**: an OpenHarmony application identified by **appid**. A bundle can contain multiple HAP files. Each application has a **bundleName**. However, **bundleName** must be used together with **appid** and other information to uniquely identify an application. +- **AbilityStage**: runtime object of an HAP. It is created when the HAP is loaded to the process for the first time and is visible to developers in the runtime. +- **Application**: runtime object of a bundle. It is invisible to developers in the runtime. +- **Context**: base class that provides APIs in the runtime to obtain information such as the bundle name, module name, and path. The **Context** classes of the Ability and ExtensionAbility components inherit from this class. +- **Ability**: provides lifecycle callbacks, holds the ability context, and supports cross-device component migration and multi-device collaboration. +- **ExtensionAbility**: general name of scenario-based Extension abilities. The system defines multiple scenario-based **ExtensionAbility** classes, each of which has its own **ExtensionContext**. +- **WindowStage**: local window manager. +- **Window**: application window, which holds an ArkUI engine instance. +- **ArkUI Page**: UI developed based on ArkUI. + + +## Lifecycle + +The ability and ability stage are key objects in the application lifecycle. + +For details about the lifecycle differences between the stage model and FA model, see [Ability Framework Overview](ability-brief.md). This section focuses on the ability lifecycle transition and the scheduling relationships between the ability, ability stage, and window stage. + +![stageabilitylifecyclecallback](figures/stageabilitylifecyclecallback.png) + +To implement device adaptation and multi-window scalability, OpenHarmony decouples the component manager from the window manager. + +The ability lifecycle defined in the stage model includes only the creation, destruction, foreground, and background states. The gain focus and lose focus states that are closely related to UI are defined in the window stage. This implements weak coupling between the abilities and windows. On the service side, the window manager notifies the component manager of the foreground and background state changes, so the component manager only senses the foreground and background state changes but not the focus changes. + +There are two lifecycle states related to the window stage in **Ability**: **onWindowStageCreate** and **onWindowStageDestroy**. They are valid only for devices with the display capability. **onWindowStageCreate** is invoked when a window stage is created, where you can call **loadContent** to set pages to be loaded for the ability. **onWindowStageDestroy** is invoked when the window stage is destroyed, where you can release resources. + + +## Ability Instances and Missions + +Abilities can be started in any of the following modes: + +* **Singleton**: For each type of ability, only one instance exists in the application process. **Ability1** in the figure below is started in singleton mode. +* **Standard**: Each time **startAbility** is called, an instance of the specified ability type is created in the application process. **Ability2** in the figure below is started in standard mode. +* **Specified**: Before creating an **Ability** instance, you can create a key for the instance. Each time **startAbility** is called, the system asks the application which ability instance (corresponding to a key) will be used. **Ability3** in the figure below is started in specified mode. + +Each **Ability** instance corresponds to a mission in **Recents**. + +The mission corresponding to an ability instance has a snapshot of the ability instance. After the ability instance is destroyed, the ability class information and snapshot are retained in the mission until the user deletes the information or the storage space reaches the upper limit. + + ![AbilityComponentInstanceMission](figures/AbilityComponentInstanceMission.png) + +## ExtensionAbility Mechanism + +Different from the ability used for UI display, ExtensionAbility provides a restricted running environment. + +ExtensionAbility has the following features: + +- Its process runs independently from the main process but shares the same storage sandbox with the main process. There is no inter-process communication (IPC) between the ExtensionAbility process and the main process. + +- It has an independent context that provides scenario-specific APIs. + +- It is created by the system, rather than by applications. + +- The lifecycles of the ExtensionAbility component and process are managed by the system. + +The following figure uses the widget an example. **FormExtensionAbility** is the base class. You can inherit from this class to provide widget information. The lifecycle of the **FormExtensionAbility** instance and that of the ExtensionAbility process where the instance is located are managed by a system service named **FormManagerService**. + +![ExtensionAbility](figures/ExtensionAbility.png) + +## Process Model + +OpenHarmony forces strong control policies on application processes. No APIs are provided to configure multiple processes. All application processes are created and managed by the system. + +The processes of an application can be classified into three types: + +- Main process: runs the **UIAbility** component, UI, and service logic. + +- Extension process: runs classes derived from **ExtensionAbility** in the application. The lifecycle of this process is managed by a scenario-specific system service. + +- Render process: created for the WebView and used to load the WebView rendering library. + + The following figure shows the process model of an application. + + ![stageprocessmodel](figures/stageprocessmodel.png) + + + +## Application Package Structure + +For details about the project directory structure of the stage model, see [OpenHarmony Project Overview](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-project-overview-0000001218440650#section56487581904). + +For details about how to configure the application package structure of the stage model, see [Application Package Structure Configuration File](../quick-start/application-configuration-file-overview-stage.md). + + \ No newline at end of file diff --git a/en/application-dev/ability-deprecated/stage-call.md b/en/application-dev/ability-deprecated/stage-call.md new file mode 100644 index 0000000000000000000000000000000000000000..e447dc4fd89f99948ebb379de7010c4db9486488 --- /dev/null +++ b/en/application-dev/ability-deprecated/stage-call.md @@ -0,0 +1,283 @@ +# Ability Call Development +## When to Use +Ability call is an extension of the ability capability. It enables an ability to be invoked by and communicate with external systems. The ability invoked can be either started in the foreground or created and run in the background. You can use the ability call to implement data sharing between two abilities (caller ability and callee ability) through inter-process communication (IPC). + +The core API used for the ability call is **startAbilityByCall**, which differs from **startAbility** in the following ways: + - **startAbilityByCall** supports ability startup in the foreground and background, whereas **startAbility** supports ability startup in the foreground only. + - The caller ability can use the **Caller** object returned by **startAbilityByCall** to communicate with the callee ability, but **startAbility** does not provide the communication capability. + +Ability call is usually used in the following scenarios: +- Communicating with the callee ability +- Starting the callee ability in the background + +**Table 1** Terms used in the ability call +|Term|Description| +|:------|:------| +|Caller ability|Ability that triggers the ability call.| +|Callee ability|Ability invoked by the ability call.| +|Caller |Object returned by **startAbilityByCall** and used by the caller ability to communicate with the callee ability.| +|Callee |Object held by the callee ability to communicate with the caller ability.| +|IPC |Inter-process communication.| + +The ability call process is as follows: + - The caller ability uses **startAbilityByCall** to obtain a **Caller** object and uses **call()** of the **Caller** object to send data to the callee ability. + - The callee ability, which holds a **Callee** object, uses **on()** of the **Callee** object to register a callback. This callback is invoked when the callee ability receives data from the caller ability. +![stage-call](figures/stage-call.png) + +> **NOTE**
+> The launch type of the callee ability must be **singleton**. +> Currently, only system applications can use the ability call. + +## Available APIs +The table below describes the ability call APIs. For details, see [Ability](../reference/apis/js-apis-application-ability.md#caller). + +**Table 2** Ability call APIs +|API|Description| +|:------|:------| +|startAbilityByCall(want: Want): Promise\|Starts an ability in the foreground (through the **want** configuration) or background (default) and obtains the **Caller** object for communication with the ability. For details, see [AbilityContext](../reference/apis/js-apis-ability-context.md#abilitycontextstartabilitybycall) or [ServiceExtensionContext](../reference/apis/js-apis-inner-application-serviceExtensionContext.md#serviceextensioncontextstartabilitybycall).| +|on(method: string, callback: CalleeCallBack): void|Callback invoked when the callee ability registers a method.| +|off(method: string): void|Callback invoked when the callee ability deregisters a method.| +|call(method: string, data: rpc.Sequenceable): Promise\|Sends agreed sequenceable data to the callee ability.| +|callWithResult(method: string, data: rpc.Sequenceable): Promise\|Sends agreed sequenceable data to the callee ability and obtains the agreed sequenceable data returned by the callee ability.| +|release(): void|Releases the **Caller** object.| +|on(type: "release", callback: OnReleaseCallback): void|Callback invoked when the **Caller** object is released.| + +## How to Develop +The procedure for developing the ability call is as follows: +1. Create a callee ability. + +2. Access the callee ability. + +### Creating a Callee Ability +For the callee ability, implement the callback to receive data and the methods to marshal and unmarshal data. When data needs to be received, use **on()** to register a listener. When data does not need to be received, use **off()** to deregister the listener. +**1. Configure the ability launch type.** + + Set **launchType** of the callee ability to **singleton** in the **module.json5** file. + +|JSON Field|Description| +|:------|:------| +|"launchType"|Ability launch type. Set this parameter to **singleton**.| + +An example of the ability configuration is as follows: +```json +"abilities":[{ + "name": ".CalleeAbility", + "srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts", + "launchType": "singleton", + "description": "$string:CalleeAbility_desc", + "icon": "$media:icon", + "label": "$string:CalleeAbility_label", + "visible": true +}] +``` +**2. Import the Ability module.** +```ts +import Ability from '@ohos.app.ability.UIAbility' +``` +**3. Define the agreed sequenceable data.** + + The data formats sent and received by the caller and callee abilities must be consistent. In the following example, the data formats are number and string. The code snippet is as follows: +```ts +export default class MySequenceable { + num: number = 0 + str: string = "" + + constructor(num, string) { + this.num = num + this.str = string + } + + marshalling(messageParcel) { + messageParcel.writeInt(this.num) + messageParcel.writeString(this.str) + return true + } + + unmarshalling(messageParcel) { + this.num = messageParcel.readInt() + this.str = messageParcel.readString() + return true + } +} +``` +**4. Implement Callee.on and Callee.off.** + + The time to register a listener for the callee ability depends on your application. The data sent and received before the listener is registered and that after the listener is deregistered are not processed. In the following example, the **MSG_SEND_METHOD** listener is registered in **onCreate** of the ability and deregistered in **onDestroy**. After receiving sequenceable data, the application processes the data and returns the data result. You need to implement processing based on service requirements. The code snippet is as follows: +```ts +const TAG: string = '[CalleeAbility]' +const MSG_SEND_METHOD: string = 'CallSendMsg' + +function sendMsgCallback(data) { + console.log('CalleeSortFunc called') + + // Obtain the sequenceable data sent by the caller ability. + let receivedData = new MySequenceable(0, '') + data.readSequenceable(receivedData) + console.log(`receiveData[${receivedData.num}, ${receivedData.str}]`) + + // Process the data. + // Return the sequenceable data result to the caller ability. + return new MySequenceable(receivedData.num + 1, `send ${receivedData.str} succeed`) +} + +export default class CalleeAbility extends Ability { + onCreate(want, launchParam) { + try { + this.callee.on(MSG_SEND_METHOD, sendMsgCallback) + } catch (error) { + console.log(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`) + } + } + + onDestroy() { + try { + this.callee.off(MSG_SEND_METHOD) + } catch (error) { + console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`) + } + } +} +``` + +### Accessing the Callee Ability +**1. Import the Ability module.** +```ts +import Ability from '@ohos.app.ability.UIAbility' +``` +**2. Obtain the Caller object.** + + The **context** attribute of the ability implements **startAbilityByCall** to obtain the **Caller** object for communication. The following example uses **this.context** to obtain the **context** attribute of the ability, uses **startAbilityByCall** to start the callee ability, obtain the **Caller** object, and register the **onRelease** listener of the caller ability. You need to implement processing based on service requirements. The code snippet is as follows: +```ts +// Register the onRelease listener of the caller ability. +private regOnRelease(caller) { + try { + caller.on("release", (msg) => { + console.log(`caller onRelease is called ${msg}`) + }) + console.log('caller register OnRelease succeed') + } catch (error) { + console.log(`caller register OnRelease failed with ${error}`) + } +} + +async onButtonGetCaller() { + try { + this.caller = await context.startAbilityByCall({ + bundleName: 'com.samples.CallApplication', + abilityName: 'CalleeAbility' + }) + if (this.caller === undefined) { + console.log('get caller failed') + return + } + console.log('get caller success') + this.regOnRelease(this.caller) + } catch (error) { + console.log(`get caller failed with ${error}`) + } +} +``` + In the cross-device scenario, you need to specify the ID of the peer device. The code snippet is as follows: +```ts +async onButtonGetRemoteCaller() { + var caller = undefined + var context = this.context + + context.startAbilityByCall({ + deviceId: getRemoteDeviceId(), + bundleName: 'com.samples.CallApplication', + abilityName: 'CalleeAbility' + }).then((data) => { + if (data != null) { + caller = data + console.log('get remote caller success') + // Register the onRelease listener of the caller ability. + caller.on("release", (msg) => { + console.log(`remote caller onRelease is called ${msg}`) + }) + console.log('remote caller register OnRelease succeed') + } + }).catch((error) => { + console.error(`get remote caller failed with ${error}`) + }) +} +``` + Obtain the ID of the peer device from **DeviceManager**. Note that the **getTrustedDeviceListSync** API is open only to system applications. The code snippet is as follows: +```ts +import deviceManager from '@ohos.distributedHardware.deviceManager'; +var dmClass; +function getRemoteDeviceId() { + if (typeof dmClass === 'object' && dmClass != null) { + var list = dmClass.getTrustedDeviceListSync() + if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { + console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null") + return + } + console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId) + return list[0].deviceId + } else { + console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null") + } +} +``` + In the cross-device scenario, your application must also apply for the data synchronization permission from end users. The code snippet is as follows: +```ts +requestPermission() { + let context = this.context + let permissions: Array = ['ohos.permission.DISTRIBUTED_DATASYNC'] + context.requestPermissionsFromUser(permissions).then((data) => { + console.log("Succeed to request permission from user with data: "+ JSON.stringify(data)) + }).catch((error) => { + console.log("Failed to request permission from user with error: "+ JSON.stringify(error)) + }) +} +``` +**3. Send agreed sequenceable data.** + + The sequenceable data can be sent to the callee ability with or without a return value. The method and sequenceable data must be consistent with those of the callee ability. The following example describes how to send data to the callee ability. The code snippet is as follows: +```ts +const MSG_SEND_METHOD: string = 'CallSendMsg' +async onButtonCall() { + try { + let msg = new MySequenceable(1, 'origin_Msg') + await this.caller.call(MSG_SEND_METHOD, msg) + } catch (error) { + console.log(`caller call failed with ${error}`) + } +} +``` + + In the following, **CallWithResult** is used to send data **originMsg** to the callee ability and assign the data processed by the **CallSendMsg** method to **backMsg**. The code snippet is as follows: +```ts +const MSG_SEND_METHOD: string = 'CallSendMsg' +originMsg: string = '' +backMsg: string = '' +async onButtonCallWithResult(originMsg, backMsg) { + try { + let msg = new MySequenceable(1, originMsg) + const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg) + console.log('caller callWithResult succeed') + + let result = new MySequenceable(0, '') + data.readSequenceable(result) + backMsg(result.str) + console.log(`caller result is [${result.num}, ${result.str}]`) + } catch (error) { + console.log(`caller callWithResult failed with ${error}`) + } +} +``` +**4. Release the Caller object.** + + When the **Caller** object is no longer required, use **release()** to release it. The code snippet is as follows: +```ts +releaseCall() { + try { + this.caller.release() + this.caller = undefined + console.log('caller release succeed') + } catch (error) { + console.log(`caller release failed with ${error}`) + } +} +``` diff --git a/en/application-dev/ability-deprecated/stage-formextension.md b/en/application-dev/ability-deprecated/stage-formextension.md new file mode 100644 index 0000000000000000000000000000000000000000..c45b33732a4f902391eb153c9f5304b071bc4f34 --- /dev/null +++ b/en/application-dev/ability-deprecated/stage-formextension.md @@ -0,0 +1,415 @@ +# Stage Widget Development + +## Widget Overview + +A widget is a set of UI components used to display important information or operations for an application. It provides users with direct access to a desired application service, without requiring them to open the application. + +A widget displays brief information about an application on the UI of another application (host application, currently system applications only) and provides basic interactive functions such as opening a UI page or sending a message. + +Basic concepts: + +- Widget provider: an atomic service that controls what and how content is displayed in a widget and interacts with users. +- Widget host: an application that displays the widget content and controls the position where the widget is displayed in the host application. +- Widget Manager: a resident agent that manages widgets added to the system and provides functions such as periodic widget update. + +> **NOTE** +> +> The widget host and provider do not keep running all the time. The Widget Manager starts the widget provider to obtain widget information when a widget is added, deleted, or updated. + +You only need to develop widget content as the widget provider. The system automatically handles the work done by the widget host and Widget Manager. + +The widget provider controls the widget content to display, component layout, and click events bound to components. + +## When to Use + +Stage widget development refers to the development conducted by the widget provider based on the [stage model](stage-brief.md). As a widget provider, you need to carry out the following operations: + +- Develop the lifecycle callbacks in **FormExtension**. +- Create a **FormBindingData** instance. +- Update a widget through **FormProvider**. +- Develop the widget UI page. + +## Available APIs + +The **FormExtension** class has the following APIs. For details, see [FormExtension](../reference/apis/js-apis-app-form-formExtensionAbility.md). + +**Table 1** FormExtension APIs + +| API | Description | +| :----------------------------------------------------------- | :------------------------------------------- | +| onCreate(want: Want): formBindingData.FormBindingData | Called to notify the widget provider that a **Form** instance (widget) has been created. | +| onCastToNormal(formId: string): void | Called to notify the widget provider that a temporary widget has been converted to a normal one.| +| onUpdate(formId: string): void | Called to notify the widget provider that a widget has been updated. | +| onVisibilityChange(newStatus: { [key: string]: number }): void | Called to notify the widget provider of the change in widget visibility. | +| onEvent(formId: string, message: string): void | Called to instruct the widget provider to receive and process a widget event. | +| onDestroy(formId: string): void | Called to notify the widget provider that a **Form** instance (widget) has been destroyed. | +| onConfigurationUpdated(config: Configuration): void; | Called when the configuration of the environment where the widget is running is updated. | + +The **FormExtension** class also has a member context, that is, the **FormExtensionContext** class. For details, see [FormExtensionContext](../reference/apis/js-apis-inner-application-formExtensionContext.md). + +**Table 2** FormExtensionContext APIs + +| API | Description | +| :----------------------------------------------------------- | :----------------------------------------------------------- | +| startAbility(want: Want, callback: AsyncCallback<void>): void | Starts an ability. This API uses an asynchronous callback to return the result. (This is a system API and cannot be called by third-party applications.)| +| startAbility(want: Want): Promise<void> | Starts an ability. This API uses a promise to return the result. (This is a system API and cannot be called by third-party applications.)| + +For details, see [FormProvider](../reference/apis/js-apis-application-formProvider.md). + +**Table 3** FormProvider APIs + +| API | Description | +| :----------------------------------------------------------- | :------------------------------------------------ | +| setFormNextRefreshTime(formId: string, minute: number, callback: AsyncCallback<void>): void; | Sets the next refresh time for a widget. This API uses an asynchronous callback to return the result. | +| setFormNextRefreshTime(formId: string, minute: number): Promise<void>; | Sets the next refresh time for a widget. This API uses a promise to return the result.| +| updateForm(formId: string, formBindingData: FormBindingData, callback: AsyncCallback<void>): void; | Updates a widget. This API uses an asynchronous callback to return the result. | +| updateForm(formId: string, formBindingData: FormBindingData): Promise<void>; | Updates a widget. This API uses a promise to return the result. | + +## How to Develop + +### Creating a FormExtension Instance + +To create a widget in the stage model, implement the lifecycle callbacks of **FormExtension**. The sample code is as follows: + +1. Import the required modules. + + ```javascript + import FormExtension from '@ohos.application.FormExtension' + import formBindingData from '@ohos.application.formBindingData' + import formInfo from '@ohos.application.formInfo' + import formProvider from '@ohos.application.formProvider' + ``` + +2. Implement the lifecycle callbacks of **FormExtension**. + + ```javascript + export default class FormAbility extends FormExtension { + onCreate(want) { + console.log('FormAbility onCreate'); + // Persistently store widget information for subsequent use, such as widget instance retrieval or update. + let obj = { + "title": "titleOnCreate", + "detail": "detailOnCreate" + }; + let formData = formBindingData.createFormBindingData(obj); + return formData; + } + onCastToNormal(formId) { + // Called when the widget host converts the temporary widget into a normal one. The widget provider should do something to respond to the conversion. + console.log('FormAbility onCastToNormal'); + } + onUpdate(formId) { + // To support scheduled update, periodic update, or update requested by the widget host, override this method for widget data update. + console.log('FormAbility onUpdate'); + let obj = { + "title": "titleOnUpdate", + "detail": "detailOnUpdate" + }; + let formData = formBindingData.createFormBindingData(obj); + formProvider.updateForm(formId, formData).catch((error) => { + console.log('FormAbility updateForm, error:' + JSON.stringify(error)); + }); + } + onVisibilityChange(newStatus) { + // Called when the widget host initiates an event about visibility changes. The widget provider should do something to respond to the notification. + console.log('FormAbility onVisibilityChange'); + } + onEvent(formId, message) { + // If the widget supports event triggering, override this method and implement the trigger. + console.log('FormAbility onEvent'); + } + onDestroy(formId) { + // Delete widget data. + console.log('FormAbility onDestroy'); + } + onConfigurationUpdated(config) { + console.log('FormAbility onConfigurationUpdated, config:' + JSON.stringify(config)); + } + } + ``` + +### Configuring the Widget Configuration File + +- Configure Extension ability information under **extensionAbilities** in the **module.json5** file. The internal field structure is described as follows: + + | Field | Description | Data Type | Default | + | ----------- | ------------------------------------------------------------ | ---------- | -------------------- | + | name | Name of the Extension ability. This field must be specified. | String | No | + | srcEntrance | Path of the Extension ability lifecycle code. This field must be specified.| String | No | + | description | Description of the Extension ability. The value can be a string or a resource index to descriptions in multiple languages.| String | Yes (initial value: left empty)| + | icon | Index of the Extension ability icon file. | String | Yes (initial value: left empty)| + | label | Descriptive information about the Extension ability presented externally. The value can be a string or a resource index to the description.| String | Yes (initial value: left empty)| + | type | Type of the Extension ability. In the current development scenario, set this field to **form**.| String | No | + | permissions | Permissions required for abilities of another application to call the current ability. | String array| Yes (initial value: left empty)| + | metadata | Metadata (configuration information) of the Extension ability.| Object | Yes (initial value: left empty) | + + For a Form Extension ability, you must specify **metadata**. Specifically, set **name** to **ohos.extension.form** (fixed), and set **resource** to the index of the widget configuration information. + + A configuration example is as follows: + + ```json + "extensionAbilities": [{ + "name": "FormAbility", + "srcEntrance": "./ets/FormAbility/FormAbility.ts", + "label": "$string:form_FormAbility_label", + "description": "$string:form_FormAbility_desc", + "type": "form", + "metadata": [{ + "name": "ohos.extension.form", + "resource": "$profile:form_config" + }] + }] + ``` + +- Configure the widget configuration information. **resource** in **metadata** specifies the index of the widget configuration information. For example, **$profile:form_config** means that **form_config.json** in the **resources/base/profile/** directory of the development view is used as the widget profile configuration file. + + The internal field structure is described as follows: + + | Field | Description | Data Type | Default | + | ------------------- | ------------------------------------------------------------ | ---------- | ------------------------ | + | name | Class name of a widget. The value is a string with a maximum of 127 bytes. | String | No | + | description | Description of the widget. The value can be a string or a resource index to descriptions in multiple languages. The value is a string with a maximum of 255 bytes.| String | Yes (initial value: left empty) | + | src | Full path of the UI code corresponding to the widget. | String | No | + | window | Window-related configurations. | Object | Yes | + | isDefault | Whether the widget is a default one. Each ability has only one default widget.
**true**: The widget is the default one.
**false**: The widget is not the default one.| Boolean | No | + | colorMode | Color mode of the widget. Available values are as follows:
**auto**: The widget adopts the auto-adaptive color mode.
**dark**: The widget adopts the dark color mode.
**light**: The widget adopts the light color mode.| String | Yes (initial value: **auto**)| + | supportDimensions | Grid styles supported by the widget. Available values are as follows:
**1 * 2**: indicates a grid with one row and two columns.
**2 * 2**: indicates a grid with two rows and two columns.
**2 * 4**: indicates a grid with two rows and four columns.
**4 * 4**: indicates a grid with four rows and four columns.| String array| No | + | defaultDimension | Default grid style of the widget. The value must be available in the **supportDimensions** array of the widget.| String | No | + | updateEnabled | Whether the widget can be updated periodically. Available values are as follows:
**true**: The widget can be updated periodically, depending on the update way you select, either at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** is recommended.
**false**: The widget cannot be updated periodically.| Boolean | No | + | scheduledUpdateTime | Scheduled time to update the widget. The value is in 24-hour format and accurate to minute.
This parameter has a lower priority than **updateDuration**. If both are specified, the value specified by **updateDuration** is used.| String | Yes (initial value: **0:0**) | + | updateDuration | Interval to update the widget. The value is a natural number, in the unit of 30 minutes.
If the value is **0**, this field does not take effect.
If the value is a positive integer ***N***, the interval is calculated by multiplying ***N*** and 30 minutes.
This parameter has a higher priority than **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| Number | Yes (initial value: **0**) | + | formConfigAbility | Link to a specific page of the application. The value is a URI. | String | Yes (initial value: left empty) | + | formVisibleNotify | Whether the widget is allowed to use the widget visibility notification. | String | Yes (initial value: left empty) | + | metaData | Metadata of the widget. This field contains the array of the **customizeData** field. | Object | Yes (initial value: left empty) | + + A configuration example is as follows: + + ```json + { + "forms": [{ + "name": "widget", + "description": "This is a widget.", + "src": "./js/widget/pages/index/index", + "window": { + "autoDesignWidth": true, + "designWidth": 720 + }, + "isDefault": true, + "colorMode": "auto", + "supportDimensions": ["2*2"], + "defaultDimension": "2*2", + "updateEnabled": true, + "scheduledUpdateTime": "10:30", + "formConfigAbility": "ability://ohos.samples.FormApplication.MainAbility" + }] + } + ``` + + +### Persistently Storing Widget Data + +Mostly, the widget provider is started only when it needs to obtain information about a widget. The Widget Manager supports multi-instance management and uses the widget ID to identify an instance. If the widget provider supports widget data modification, it must persistently store the data based on the widget ID, so that it can access the data of the target widget when obtaining, updating, or starting the widget. + +```javascript + onCreate(want) { + console.log('FormAbility onCreate'); + + let formId = want.parameters["ohos.extra.param.key.form_identity"]; + let formName = want.parameters["ohos.extra.param.key.form_name"]; + let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"]; + // Persistently store widget data for subsequent use, such as widget instance retrieval or update. + // The storeFormInfo API is not implemented here. + storeFormInfo(formId, formName, tempFlag, want); + + let obj = { + "title": "titleOnCreate", + "detail": "detailOnCreate" + }; + let formData = formBindingData.createFormBindingData(obj); + return formData; + } +``` + +You should override **onDestroy** to delete widget data. + +```javascript + onDestroy(formId) { + console.log('FormAbility onDestroy'); + + // You need to implement the code for deleting the persistent widget data. + // The deleteFormInfo API is not implemented here. + deleteFormInfo(formId); + } +``` + +For details about the persistence method, see [Lightweight Data Store Development](../database/database-preference-guidelines.md). + +Note that the **Want** passed by the widget host to the widget provider contains a temporary flag, indicating whether the requested widget is a temporary one. + +- Normal widget: a widget that will be persistently used by the widget host + +- Temporary widget: a widget that is temporarily used by the widget host + +Data of a temporary widget is not persistently stored. If it is deleted from the Widget Manager due to exceptions, such as crash of the widget framework, the widget provider will not be notified of which widget is deleted, and still keeps the data. In light of this, the widget provider should implement data clearing. If the widget host successfully converts a temporary widget into a normal one, the widget provider should also process the widget ID and store the data persistently. This prevents the widget provider from deleting the widget data when clearing temporary widgets. + +### Updating Widget Data + +When a widget application initiates a data update upon a scheduled or periodic update, the application obtains the latest data and calls **updateForm** to update the widget. The sample code is as follows: + +```javascript +onUpdate(formId) { + // To support scheduled update, periodic update, or update requested by the widget host, override this method for widget data update. + console.log('FormAbility onUpdate'); + let obj = { + "title": "titleOnUpdate", + "detail": "detailOnUpdate" + }; + let formData = formBindingData.createFormBindingData(obj); + // Call the updateForm method to update the widget. Only the data passed through the input parameter is updated. Other information remains unchanged. + formProvider.updateForm(formId, formData).catch((error) => { + console.log('FormAbility updateForm, error:' + JSON.stringify(error)); + }); +} +``` + +### Developing the Widget UI Page + +You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programmed widget. + +> **NOTE** +> +> Currently, only the JavaScript-based web-like development paradigm can be used to develop the widget UI. + + - In the HML file: + ```html +
+ +
+ +
+
+ {{title}} + {{detail}} +
+
+
+ ``` + + - In the CSS file: + + ```css +.container { + flex-direction: column; + justify-content: center; + align-items: center; +} + +.bg-img { + flex-shrink: 0; + height: 100%; +} + +.container-inner { + flex-direction: column; + justify-content: flex-end; + align-items: flex-start; + height: 100%; + width: 100%; + padding: 12px; +} + +.title { + font-size: 19px; + font-weight: bold; + color: white; + text-overflow: ellipsis; + max-lines: 1; +} + +.detail_text { + font-size: 16px; + color: white; + opacity: 0.66; + text-overflow: ellipsis; + max-lines: 1; + margin-top: 6px; +} + ``` + + - In the JSON file: + ```json + { + "data": { + "title": "TitleDefault", + "detail": "TextDefault" + }, + "actions": { + "routerEvent": { + "action": "router", + "abilityName": "MainAbility", + "params": { + "message": "add detail" + } + } + } + } + ``` + +Now you've got a widget shown below. + +![fa-form-example](figures/fa-form-example.png) + +### Developing Widget Events + +You can set router and message events for components on a widget. The router event applies to ability redirection, and the message event applies to custom click events. The key steps are as follows: + +1. Set **onclick** in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file. +2. For the router event, set the following attributes: + - **action**: **"router"**. + - **abilityName**: target ability name, for example, **MainAbility**, which is the default main ability name in DevEco Studio for the stage model. + - **params**: custom parameters of the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the main ability in the stage model, you can obtain **want** and its **parameters** field. +3. For the message event, set the following attributes: + - **action**: **"message"**. + - **params**: custom parameters of the message event. Set them as required. The value can be obtained from **message** in the widget lifecycle function **onEvent**. + +The following is an example: + + - In the HML file: + ```html +
+ +
+ +
+
+ {{title}} + {{detail}} +
+
+
+ ``` + + - In the JSON file: + ```json + { + "data": { + "title": "TitleDefault", + "detail": "TextDefault" + }, + "actions": { + "routerEvent": { + "action": "router", + "abilityName": "MainAbility", + "params": { + "message": "add detail" + } + }, + "messageEvent": { + "action": "message", + "params": { + "message": "add detail" + } + } + } + } + ``` diff --git a/en/application-dev/ability-deprecated/stage-serviceextension.md b/en/application-dev/ability-deprecated/stage-serviceextension.md new file mode 100644 index 0000000000000000000000000000000000000000..98cae5914f7afa34c916c53f6bb423b590cf5070 --- /dev/null +++ b/en/application-dev/ability-deprecated/stage-serviceextension.md @@ -0,0 +1,75 @@ +# Service Extension Ability Development + +## When to Use +`ExtensionAbility` is the base class of the new Extension component in the stage model. It is used to process missions without UIs. The lifecycle of an Extension ability is simple and does not involve foreground or background states. `ServiceExtensionAbility` is extended from `ExtensionAbility`. + +You can customize a class that inherits from `ServiceExtensionAbility` and override the lifecycle callbacks in the base class to perform service logic operations during the initialization, connection, and disconnection processes. + +## Available APIs + +**Table 1** ServiceExtensionAbility lifecycle APIs +|API|Description| +|:------|:------| +|onCreate(want: Want): void|Called for the initialization when `startAbility` or `connectAbility` is invoked for a given ability for the first time.| +|onRequest(want: Want, startId: number): void|Called each time `startAbility` is invoked for a given ability. The initial value of `startId` is `1`, and the value is incremented by one each time `startAbility` is invoked for that ability.| +|onConnect(want: Want): rpc.RemoteObject|Called when `connectAbility` is invoked for a given ability. This callback is not invoked for repeated calling of `connectAbility` for a specific ability. However, it will be invoked unless `connectAbility` is called after the ability has been disconnected using `disconnectAbility`. The returned result is a `RemoteObject`.| +|onDisconnect(want: Want): void|Called when `disconnectAbility` is called for a given ability. If the Extension ability is started by `connectAbility` and is not bound to other applications, the `onDestroy` callback will also be triggered to destroy the Extension ability.| +|onDestroy(): void|Called when `terminateSelf` is invoked to terminate the ability.| + + +## Constraints + +OpenHarmony does not support creation of a Service Extension ability for third-party applications. + + +## How to Develop + +1. Declare the Service Extension ability in the `module.json5` file by setting its `type` attribute to `service`. The following is a configuration example of the `module.json5` file: + + + ```json + "extensionAbilities":[{ + "name": "ServiceExtAbility", + "icon": "$media:icon", + "description": "service", + "type": "service", + "visible": true, + "srcEntrance": "./ets/ServiceExtAbility/ServiceExtAbility.ts" + }] + ``` + + +2. Customize a class that inherits from `ServiceExtensionAbility` in the .ts file in the directory where the Service Extension ability is defined (`entry\src\main\ets\ServiceExtAbility\ServiceExtAbility.ts` by default) and override the lifecycle callbacks of the base class. The code sample is as follows: + + ```js + import ServiceExtensionAbility from '@ohos.application.ServiceExtensionAbility' + import rpc from '@ohos.rpc' + + class StubTest extends rpc.RemoteObject { + constructor(des) { + super(des); + } + onRemoteRequest(code, data, reply, option) { + } + } + + class ServiceExtAbility extends ServiceExtensionAbility { + onCreate(want) { + console.log('onCreate, want:' + want.abilityName); + } + onRequest(want, startId) { + console.log('onRequest, want:' + want.abilityName); + } + onConnect(want) { + console.log('onConnect , want:' + want.abilityName); + return new StubTest("test"); + } + onDisconnect(want) { + console.log('onDisconnect, want:' + want.abilityName); + } + onDestroy() { + console.log('onDestroy'); + } + } + ``` + diff --git a/en/application-dev/ability-deprecated/wantagent.md b/en/application-dev/ability-deprecated/wantagent.md new file mode 100644 index 0000000000000000000000000000000000000000..4b1854d1a54a36f864b3dd4215040eb24db2e5f3 --- /dev/null +++ b/en/application-dev/ability-deprecated/wantagent.md @@ -0,0 +1,86 @@ +# WantAgent Development +## When to Use +The **WantAgent** class encapsulates want information that specifies a particular action, which can be starting an ability or publishing a common event. You can either call **wantAgent.trigger** to trigger a **WantAgent** directly or add a **WantAgent** to a notification so that it will be triggered when users tap the notification. + +## Available APIs +| API | Description| +| ---------------------------------------------------------------------------------------------- | ----------- | +| getWantAgentInfo(info: WantAgentInfo, callback: AsyncCallback\) | Creates a **WantAgent** object. This API uses an asynchronous callback to return the result.| +| getWantAgent(info: WantAgentInfo): Promise\ | Creates a **WantAgent** object. This API uses a promise to return the result.| +| trigger(agent: WantAgent, triggerInfo: TriggerInfo, callback?: Callback\) | Triggers a **WantAgent** object.| + +## How to Develop +1. Import the **WantAgent** module. + + ``` + import wantAgent from '@ohos.wantAgent'; + ``` + +2. Create a **WantAgentInfo** object that will be used for starting an ability. For details about the data types and parameters of **WantAgentInfo**, see [WantAgent](../reference/apis/js-apis-wantAgent.md#wantagentinfo). + + ``` + private wantAgentObj = null // Save the WantAgent object created. It will be used to complete the trigger operations. + + // wantAgentInfo + var wantAgentInfo = { + wants: [ + { + deviceId: "", + bundleName: "com.example.test", + abilityName: "com.example.test.MainAbility", + action: "", + entities: [], + uri: "", + parameters: {} + } + ], + operationType: wantAgent.OperationType.START_ABILITY, + requestCode: 0, + wantAgentFlags:[wantAgent.WantAgentFlags.CONSTANT_FLAG] + } + ``` + +3. Create a **WantAgentInfo** object for publishing a common event. + + ``` + private wantAgentObj = null // Save the WantAgent object created. It will be used to complete the trigger operations. + + // wantAgentInfo + var wantAgentInfo = { + wants: [ + { + action: "event_name", // Set the action name. + parameters: {} + } + ], + operationType: wantAgent.OperationType.SEND_COMMON_EVENT, + requestCode: 0, + wantAgentFlags:[wantAgent.WantAgentFlags.CONSTANT_FLAG] + } + ``` + +4. Create a **WantAgent** object and save the returned **wantAgentObj** for subsequent trigger operations. + + ``` + // Create a WantAgent object. + wantAgent.getWantAgent(wantAgentInfo, (err, wantAgentObj) => { + if (err.code) { + console.error("[WantAgent]getWantAgent err=" + JSON.stringify(err)) + } else { + console.log("[WantAgent]getWantAgent success") + this.wantAgentObj = wantAgentObj + } + }) + ``` + +5. Trigger the **WantAgent** object. + + ``` + // Trigger the WantAgent object. + var triggerInfo = { + code:0 + } + wantAgent.trigger(wantAgentObj, triggerInfo, (completeData) => { + console.log("[WantAgent]getWantAgent success, completeData: ", + JSON.stringify(completeData)) + }) + ``` diff --git a/en/application-dev/ability/Readme-EN.md b/en/application-dev/ability/Readme-EN.md deleted file mode 100644 index 0589643e0f9426f76ac25d3616a41c3b54910e2a..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/Readme-EN.md +++ /dev/null @@ -1,23 +0,0 @@ -# Ability Development -- [Ability Framework Overview](ability-brief.md) -- [Context Usage](context-userguide.md) -- FA Model - - [FA Model Overview](fa-brief.md) - - [Page Ability Development](fa-pageability.md) - - [Service Ability Development](fa-serviceability.md) - - [Data Ability Development](fa-dataability.md) - - [FA Widget Development](fa-formability.md) -- Stage Model - - [Stage Model Overview](stage-brief.md) - - [Ability Development](stage-ability.md) - - [Service Extension Ability Development](stage-serviceextension.md) - - [Ability Continuation Development](stage-ability-continuation.md) - - [Ability Call Development](stage-call.md) - - [Stage Widget Development](stage-formextension.md) -- Other - - [WantAgent Development](wantagent.md) - - [Ability Assistant Usage](ability-assistant-guidelines.md) - - [ContinuationManager Development](continuationmanager.md) - - [Test Framework Usage](ability-delegator.md) - - diff --git a/en/application-dev/ability/ability-assistant-guidelines.md b/en/application-dev/ability/ability-assistant-guidelines.md deleted file mode 100644 index 4d7b0edb2b91ca07123ad7495f4d64fc2f525e1d..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/ability-assistant-guidelines.md +++ /dev/null @@ -1,107 +0,0 @@ -# Ability Assistant Usage - -The ability assistant enables you to start applications, atomic services, and test cases and debug applications. By using this tool, you can send commands in the hdc shell to perform various system operations, such as starting abilities, forcibly stopping processes, and printing ability information. - -## Query-related Commands - -- **help** - - Displays help information for the ability assistant. - - **Return value** - - Returns the help information. - - **Method** - - ``` - aa help - ``` - -## Ability-related Commands - -- **start** - - Starts an ability. - - | Name | Description | - | --------- | -------------------------- | - | -h/--help | Help information. | - | -d | Device ID. This parameter is optional. | - | -a | Ability name. This parameter is mandatory.| - | -b | Bundle name. This parameter is mandatory. | - | -D | Debugging mode. This parameter is optional. | - - **Return value** - - Returns "start ability successfully." if the ability is started; returns "error: failed to start ability." otherwise. - - **Method** - - ``` - aa start [-d ] -a -b [-D] - ``` - -- **stop-service** - - Stops a Service ability. - - | Name | Description | - | --------- | ------------------------ | - | -h/--help | Help information. | - | -d | Device ID. This parameter is optional. | - | -a | Ability name. This parameter is mandatory.| - | -b | Bundle name. This parameter is mandatory. | - - **Return value** - - Returns "stop service ability successfully." if the Service ability is stopped; returns "error: failed to stop service ability." otherwise. - - **Method** - - ``` - aa stop-service [-d ] -a -b - ``` - -- **dump** - - Prints ability-related information. - - | Name | Level-2 Parameter | Description | - | ----------------- | -------------------- | ------------------------------------------------------------ | - | -h/--help | - | Prints help information. | - | -a/--all | - | Prints ability information in all missions. | - | -l/--mission-list | type (All logs are printed if this parameter is left unspecified.)| Prints mission stack information.
The following values are available for **type**:
- NORMAL
- DEFAULT_STANDARD
- DEFAULT_SINGLE
- LAUNCHER | - | -e/--extension | elementName | Prints extended component information. | - | -u/--userId | UserId | Prints stack information of a specified user ID. This parameter must be used together with other parameters.
Example commands: aa **dump -a -u 100** and **aa dump -d -u 100**. | - | -d/--data | - | Prints Data ability information. | - | -i/--ability | AbilityRecord ID | Prints detailed information about a specified ability. | - | -c/--client | - | Prints detailed ability information. This parameter must be used together with other parameters.
Example commands: **aa dump -a -c** and **aa dump -i 21 -c**. | - - **Method** - - ``` - aa dump -a - ``` - ![aa-dump-a](figures/aa-dump-a.PNG) - ``` - aa dump -l - ``` - ![aa-dump-l](figures/aa-dump-l.PNG) - ``` - aa dump -i 12 - ``` - ![aa-dump-i](figures/aa-dump-i.PNG) -- **force-stop** - - Forcibly stops a process based on the bundle name. - - **Return value** - - Returns "force stop process successfully." if the process is forcibly stopped; returns "error: failed to force stop process." otherwise. - - **Method** - - ``` - aa force-stop - ``` diff --git a/en/application-dev/ability/ability-brief.md b/en/application-dev/ability/ability-brief.md deleted file mode 100644 index 0d2303bf4f84c2ddc6f34a13d28b02a3762893b0..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/ability-brief.md +++ /dev/null @@ -1,30 +0,0 @@ -# Ability Framework Overview - -An ability is the abstraction of a functionality that an application can provide. It is the minimum unit for the system to schedule applications. An application can contain one or more `Ability` instances. - -The ability framework model has two forms: - -- FA model, which applies to application development using API version 8 and earlier versions. In the FA model, there is Feature Ability (FA) and Particle Ability (PA). The FA supports Page abilities, and the PA supports Service, Data, and Form abilities. -- Stage model, which is introduced since API version 9. In the stage model, there is `Ability` and `ExtensionAbility`. `ExtensionAbility` is further extended to `ServiceExtensionAbility`, `FormExtensionAbility`, `DataShareExtensionAbility`, and more. - -The stage model is designed to make it easier to develop complex applications in the distributed environment. The table below lists the design differences between the two models. - -| Item | FA Model | Stage Model | -| -------------- | ------------------------------------------------------------ | -------------------------------------------------------- | -| Development mode | Web-like APIs are provided. The UI development is the same as that of the stage model. | Object-oriented development mode is provided. The UI development is the same as that of the FA model. | -| Engine instance | Each ability in a process exclusively uses a JS VM engine instance. | Multiple abilities in a process share one JS VM engine instance. | -| Intra-process object sharing| Not supported. | Supported. | -| Bundle description file | The `config.json` file is used to describe the HAP and component information. Each component must use a fixed file name.| The `module.json5` file is used to describe the HAP and component information. The entry file name can be specified.| -| Component | Four types of components are provided: Page ability (used for UI page display), Service ability (used to provide services), Data ability (used for data sharing), and Form ability (used to provide widgets).| Two types of components are provided: Ability (used for UI page display) and Extension (scenario-based service extension). | - -In addition, the following differences exist in the development process: - -* Different ability types - - ![favsstage](figures/favsstage.png) - -* Different ability lifecycles - - ![lifecycle](figures/lifecycle.png) - -For details about the two models, see [FA Model Overview](fa-brief.md) and [Stage Model Overview](stage-brief.md). diff --git a/en/application-dev/ability/ability-delegator.md b/en/application-dev/ability/ability-delegator.md deleted file mode 100644 index 5fd0293efde6d6d264be28b6c30123e7697bee6b..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/ability-delegator.md +++ /dev/null @@ -1,181 +0,0 @@ -# Test Framework Usage - -## Overview -The delegator test framework provides a self-test environment for OpenHarmony applications. Using this framework, you can start an ability, schedule its lifecycle, listen for its state changes, run a shell command, and print the test result. - -## Constraints - -The APIs provided by the test framework can be used only in the test HAP. They take effect only after the test framework is started. - - -## Starting the Test Framework - -The test framework can be started in either of the following ways: - -- Method 1: Run the `aa test` command. -- Method 2: Use DevEco Studio. - -### Running aa test - -To start the test framework, specify the **TestRunner** and the package name or module name of the HAP where the **TestRunner** is located. - -An example command in the FA model is as follows: - -```javascript -aa test -b BundleName -p com.example.myapplicationfaets -s unittest OpenHarmonyTestRunner -s class ActsAbilityTest -w 20 -``` - -An example command in the stage model is as follows: -```javascript -aa test -b BundleName -m com.example.myapplicationfaets -s unittest OpenHarmonyTestRunner -s class ActsAbilityTest -w 20 -``` -| Parameter | Mandatory| Description | -| --------------- | -------- | ------------------------------------------------------------ | -| -b | Yes | Bundle name of the HAP where the **TestRunner** is located. | -| -p | Yes | Package name of the HAP where the **TestRunner** is located. This parameter is used by the FA model. | -| -m | Yes | Module name of the HAP where the **TestRunner** is located. This parameter is used by the stage model. | -| -s unittest | Yes | Name of the **TestRunner** to be used. The TestRunner name must be the same as the file name. | -| -w | No | Timeout interval of a test case, in seconds. If this parameter is not specified or is set to a value less than or equal to **0**, the test framework exits only after **finishTest** is invoked.| -| -s \\ | No | **-s** can be followed by any key-value pair obtained through **AbilityDelegatorArgs.parameters**. For example, in **-s classname myTest**, **-s classname** is the key and **myTest** is the value.| -| -D | No | Debug mode for starting the tested application.| -| -h | No | Help information.| - -### Using DevEco Studio - -For details about how to use DevEco Studio to start the test framework, see [OpenHarmony Test Framework](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-openharmony-test-framework-0000001263160453#section1034420367508). - -## Introduction to TestRunner - -**TestRunner** is the entry class of the test framework test process. When the test process is started, the system calls related APIs in **TestRunner**. You need to inherit this class and override the **onPrepare** and **onRun** APIs. When creating an application template, DevEco Studio initializes the default **TestRunner** and starts the default **TestAbility** in the **onRun** API. You can modify the test code of **TestAbility** or override **onPrepare** and **onRun** in **TestRunner** to implement your own test code. For details, see [TestRunner](../reference/apis/js-apis-testRunner.md). - -## Introduction to AbilityDelegatorRegistry - -**AbilityDelegatorRegistry** is the **AbilityDelegator** repository class provided by the test framework. You can use **AbilityDelegatorRegistry** to obtain an **AbilityDelegator** instance and the input and generated parameters **AbilityDelegatorArgs** during the test. You can use **AbilityDelegator** to invoke the function set provided by the test framework for testing and verification. For details, see [AbilityDelegatorRegistry](../reference/apis/js-apis-abilityDelegatorRegistry.md). - -## Introduction to AbilityDelegatorArgs - -**AbilityDelegatorArgs** is a test parameter class provided by the test framework. You can use **AbilityDelegatorArgs** to obtain the parameters passed and generated during the test. For details, see [AbilityDelegatorArgs](../reference/apis/js-apis-application-abilityDelegatorArgs.md). - -## Introduction to AbilityMonitor - -**AbilityMonitor** is provided by the test framework for binding to and listening for abilities. You can use **AbilityMonitor** to bind to an **Ability** instance and add **AbilityMonitor** to the listening list. When **AbilityMonitor** is bound to an ability, the creation and lifecycle changes of the ability will trigger the related callback in **AbilityMonitor**. You can test and verify the ability in these callbacks. For details, see [AbilityMonitor](../reference/apis/js-apis-application-abilityMonitor.md). - -**Example** - -```javascript -import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' - -function onAbilityCreateCallback(data) { - console.info("onAbilityCreateCallback"); -} - -var monitor = { - abilityName: "abilityname", - onAbilityCreate: onAbilityCreateCallback -} - -var abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); -abilityDelegator.addAbilityMonitor(monitor).then(() => { - console.info("addAbilityMonitor promise"); -}); -``` - -## Introduction to AbilityDelegator - -**AbilityDelegator** is a main function class of the test framework. It provides the functions of starting an ability, obtaining an **Ability** instance, scheduling the ability lifecycle, listening for the ability state, and printing test results. - -**Modules to Import** - -```javascript -import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' -``` - -```javascript -var abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() -``` - -### Starting an Ability and Listening for the Ability State - -Use **AbilityDelegator** and **AbilityMonitor** to start an ability, obtain an **Ability** instance, and listen for the ability state. - -**Example** - -```javascript -var abilityDelegator; -var ability; -var timeout = 100; - -function onAbilityCreateCallback(data) { - console.info("onAbilityCreateCallback"); -} - -var monitor = { - abilityName: "abilityname", - onAbilityCreate: onAbilityCreateCallback -} - -abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); -abilityDelegator.waitAbilityMonitor(monitor, timeout, (err, data) => { - ability = data; - console.info("waitAbilityMonitor callback"); -}); - -var want = { - bundleName: "bundleName", - abilityName: "abilityName" -}; -abilityDelegator.startAbility(want, (err, data) => { - console.info("startAbility callback"); -}); -``` - -### Scheduling the Ability Lifecycle - -**AbilityDelegator** provides APIs to display and schedule the ability lifecycle and supports the foreground and background. It works with **AbilityMonitor** to listen for the ability lifecycle. For details, see [AbilityDelegator](../reference/apis/js-apis-application-abilityDelegator.md). - -### Running a Shell Command - -**AbilityDelegator** provides APIs to run shell commands in the test environment. - -**Example** - -```javascript -var abilityDelegator; -var cmd = "cmd"; -abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); -abilityDelegator.executeShellCommand(cmd, (err, data) => { - console.info("executeShellCommand callback"); -}); -``` - -### Printing Log Information - -**AbilityDelegator** provides APIs for printing log information. You can call any API in the test code to print process logs to the unit test console. - -**Example** - -```javascript -var abilityDelegator; -var msg = "msg"; - -abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); -abilityDelegator.print(msg, (err) => { - console.info("print callback"); -}); -``` - -### Finishing the Test and Printing Log Information - -**AbilityDelegator** provides the APIs for actively finishing the test. You can call any API in test code to finish the test and print logs to the unit test console. - -**Example** - -```javascript -var abilityDelegator; -var msg = "msg"; - -abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); -abilityDelegator.finishTest(msg, 0, (err) => { - console.info("finishTest callback"); -}); -``` diff --git a/en/application-dev/ability/context-userguide.md b/en/application-dev/ability/context-userguide.md deleted file mode 100644 index d3e681244166cafecff86575dd1850db4ebf7f90..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/context-userguide.md +++ /dev/null @@ -1,312 +0,0 @@ -# Context Usage - -## Context Overview - -**Context** provides the capability of obtaining contextual information of an application. - -The OpenHarmony application framework has two models: Feature Ability (FA) model and stage model. Correspondingly, there are two sets of context mechanisms. **application/BaseContext** is a common context base class. It uses the **stageMode** attribute to specify whether the context is used for the stage model. - -- FA model - - Only the methods in **app/Context** can be used for the context in the FA model. Both the application-level context and ability-level context are instances of this type. If an ability-level method is invoked in the application-level context, an error occurs. Therefore, you must pay attention to the actual meaning of the **Context** instance. - -- Stage model - - The stage model has the following types of contexts: **application/Context**, **application/ApplicationContext**, **application/AbilityStageContext**, **application/ExtensionContext**, **application/AbilityContext**, and **application/FormExtensionContext**. For details about these contexts and how to use them, see [Context in the Stage Model](#context-in-the-stage-model). - -![contextIntroduction](figures/contextIntroduction.png) - -## Context in the FA Model - -Only the methods in **app/Context** can be used for the context in the FA model. - -The FA model has only one context definition. All capabilities in the context are provided through methods. The context uses these methods to extend the capabilities of the FA. - -**d.ts statement** - -https://gitee.com/openharmony/interface_sdk-js/blob/master/api/app/context.d.ts - -**Example** - -```javascript -import featureAbility from '@ohos.ability.featureAbility' -export default { - onCreate() { - // Obtain the context and call related APIs. - let context = featureAbility.getContext(); - context.getBundleName((data, bundleName)=>{ - console.info("ability bundleName:" + bundleName) - }); - console.info('Application onCreate') - }, - onDestroy() { - console.info('Application onDestroy') - }, -} -``` - -### Common Context-related Methods in the FA Model -The following context-related methods are available in the FA model: -```javascript -setDisplayOrientation(orientation: bundle.DisplayOrientation, callback: AsyncCallback): void -setDisplayOrientation(orientation: bundle.DisplayOrientation): Promise; -``` -The methods are used to set the display orientation of the current ability. - -**Example** -```javascript -import featureAbility from '@ohos.ability.featureAbility' -import bundle from '../@ohos.bundle'; - -export default { - onCreate() { - // Obtain the context and call related APIs. - let context = featureAbility.getContext(); - context.setDisplayOrientation(bundle.DisplayOrientation.LANDSCAPE).then(() => { - console.log("Set display orientation.") - }) - console.info('Application onCreate') - }, - onDestroy() { - console.info('Application onDestroy') - }, -} -``` - -## Context in the Stage Model - -The following describes the contexts provided by the stage model in detail. - -### application/Context - -**application/Context** is the base class context that provides basic application information such as **resourceManager**, **applicationInfo**, **cacheDir**, and **area**. It also provides basic application methods such as **createBundleContext**. - -**d.ts statement** - -https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/Context.d.ts - -### application/ApplicationContext - -**application/ApplicationContext** is an application-level context. In addition to the capabilities provided by the base class context, the application-level context provides **registerAbilityLifecycleCallback** and **unregisterAbilityLifecycleCallback** to monitor the ability lifecycle in a process. - -**How to Obtain** - -Obtain the context by calling **context.getApplicationContext()** in **Ability**. - -**Example** - -```javascript -import AbilityStage from "@ohos.application.AbilityStage"; - -var lifecycleid; - -export default class MyAbilityStage extends AbilityStage { - onCreate() { - console.log("MyAbilityStage onCreate") - let AbilityLifecycleCallback = { - onAbilityCreate(ability){ - console.log("AbilityLifecycleCallback onAbilityCreate ability:" + JSON.stringify(ability)); - }, - onWindowStageCreate(ability, windowStage){ - console.log("AbilityLifecycleCallback onWindowStageCreate ability:" + JSON.stringify(ability)); - console.log("AbilityLifecycleCallback onWindowStageCreate windowStage:" + JSON.stringify(windowStage)); - }, - onWindowStageActive(ability, windowStage){ - console.log("AbilityLifecycleCallback onWindowStageActive ability:" + JSON.stringify(ability)); - console.log("AbilityLifecycleCallback onWindowStageActive windowStage:" + JSON.stringify(windowStage)); - }, - onWindowStageInactive(ability, windowStage){ - console.log("AbilityLifecycleCallback onWindowStageInactive ability:" + JSON.stringify(ability)); - console.log("AbilityLifecycleCallback onWindowStageInactive windowStage:" + JSON.stringify(windowStage)); - }, - onWindowStageDestroy(ability, windowStage){ - console.log("AbilityLifecycleCallback onWindowStageDestroy ability:" + JSON.stringify(ability)); - console.log("AbilityLifecycleCallback onWindowStageDestroy windowStage:" + JSON.stringify(windowStage)); - }, - onAbilityDestroy(ability){ - console.log("AbilityLifecycleCallback onAbilityDestroy ability:" + JSON.stringify(ability)); - }, - onAbilityForeground(ability){ - console.log("AbilityLifecycleCallback onAbilityForeground ability:" + JSON.stringify(ability)); - }, - onAbilityBackground(ability){ - console.log("AbilityLifecycleCallback onAbilityBackground ability:" + JSON.stringify(ability)); - }, - onAbilityContinue(ability){ - console.log("AbilityLifecycleCallback onAbilityContinue ability:" + JSON.stringify(ability)); - } - } - // 1. Obtain applicationContext through the context attribute. - let applicationContext = this.context.getApplicationContext(); - // 2. Use applicationContext to register and listen for the ability lifecycle in the application. - lifecycleid = applicationContext.registerAbilityLifecycleCallback(AbilityLifecycleCallback); - console.log("registerAbilityLifecycleCallback number: " + JSON.stringify(lifecycleid)); - } - onDestroy() { - let applicationContext = this.context.getApplicationContext(); - applicationContext.unregisterAbilityLifecycleCallback(lifecycleid, (error, data) => { - console.log("unregisterAbilityLifecycleCallback success, err: " + JSON.stringify(error)); - }); - } -} -``` - -**d.ts statement** - -https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/ApplicationContext.d.ts - -### application/AbilityStageContext - -**application/AbilityStageContext** is the context for the HAP file. In addition to those provided by the base class **application/Context**, this context contains **HapModuleInfo** and **Configuration**. - -**How to Obtain** - -Obtain the context from the **context** attribute in **AbilityStage**. - -**Example** - -```javascript -export default class MyAbilityStage extends AbilityStage { - onCreate() { - // The context attribute is of the AbilityStageContext type. - console.log('HapModuleInfo is ' + this.context.currentHapModuleInfo); - } -} -``` - -**d.ts statement** - -https://gitee.com/openharmony/interface_sdk-js/blob/master/api/application/AbilityStageContext.d.ts - -### application/AbilityContext - -In the stage model, each ability has a context attribute. - -**Ability** provides methods to manage the ability lifecycle, and **AbilityContext** provides methods to operate abilities (such as **startAbility** and **connectAbility**). - -**How to Obtain** - -Obtain the context from the **context** attribute in **Ability**. - -**Example** - -```javascript -import Ability from '@ohos.application.Ability' - -export default class MainAbility extends Ability { - onCreate(want, launchParam) { - console.log("[Demo] MainAbility onCreate") - globalThis.abilityWant = want; - } - - onDestroy() { - console.log("[Demo] MainAbility onDestroy") - } - - onWindowStageCreate(windowStage) { - // Set the main page for this ability when the main window is created. - console.log("[Demo] MainAbility onWindowStageCreate") - - // Obtain AbilityContext and print the ability information. - let context = this.context; - console.log("[Demo] MainAbility bundleName " + context.abilityInfo.bundleName) - - windowStage.setUIContent(this.context, "pages/index", null) - } - - onWindowStageDestroy() { - // Release the UI related resources when the main window is destroyed. - console.log("[Demo] MainAbility onWindowStageDestroy") - } - - onForeground() { - // The ability is switched to run in the foreground. - console.log("[Demo] MainAbility onForeground") - } - - onBackground() { - // The ability is switched to run in the background. - console.log("[Demo] MainAbility onBackground") - } -}; -``` - -### application/FormExtensionContext - -For details, see [FormExtensionContext](../reference/apis/js-apis-formextensioncontext.md). - -### Obtaining the Context on an eTS Page - -In the stage model, in the `onWindowStageCreate` lifecycle of an ability, you can call `SetUIContent` of `WindowStage` to load an eTS page. In some scenarios, you need to obtain the context on the page to call related APIs. - -**How to Obtain** - -Use the API described in the table below to obtain the context associated with an eTS page. - -| API | Description | -| :------------------------------------ | :--------------------------- | -| getContext(component: Object): Object | Obtains the `Context` object associated with a component on the page.| - -**Example** - -```ts -// MainAbility.ts -import Ability from '@ohos.application.Ability' - -export default class MainAbility extends Ability { - onCreate(want, launchParam) { - console.log("[Demo] MainAbility onCreate") - } - - onDestroy() { - console.log("[Demo] MainAbility onDestroy") - } - - onWindowStageCreate(windowStage) { - // Load the index page and pass the current Context object. - windowStage.setUIContent(this.context, "pages/index", null) - } - - onWindowStageDestroy() {} - - onForeground() {} - - onBackground() {} -}; -``` - -```ts -// pages/index.ets -import context from '@ohos.application.context' - -type Context = context.Context - -@Entry -@Component -struct Index { - build() { - Row() { - Column() { - Text('GetContext') - .fontSize(50) - .fontWeight(FontWeight.Bold) - .onClick(() => { - // Obtain the Context object associated with the current component. - var context : Context = getContext(this) as Context - console.info("CacheDir:" + context.cacheDir) - }) - } - .width('100%') - } - .height('100%') - } -} -``` - -## Common Incorrect Usage - -**Error 1: Use globalThis to obtain the context in the stage model.** - -**Reason** - -In the FA model, each ability instance has a JS VM instance. Therefore, a global ability instance can be obtained from the **global** object of the JS engine. In the stage model, where all the processes of an application share a JS VM instance, there is no global ability instance, and using **globalThis** may cause an error or crash. diff --git a/en/application-dev/ability/continuationmanager.md b/en/application-dev/ability/continuationmanager.md deleted file mode 100644 index a1f5a66478cd53aeabe03ed9be21e08596cb2b6b..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/continuationmanager.md +++ /dev/null @@ -1,253 +0,0 @@ -# ContinuationManager Development - -> **NOTE** -> -> Currently, the **ContinuationManager** module is not available for application development. Its APIs are mainly used to start the device selection module. - -## When to Use -Users are using two or more devices to experience an all-scenario, multi-device lifestyle. Each type of device has its unique advantages and disadvantages specific to scenarios. The ability continuation capability breaks boundaries of devices and enables multi-device collaboration, achieving precise control, universal coordination, and seamless hops of user applications. - -As the entry of the ability continuation capability, **continuationManager** is used to start the device selection module for the user to select the target device. After a device is selected, information about the selected device is returned to the user. The user can then initiate cross-device continuation or collaboration based on the device information. - -![continuationManager](figures/continuationManager.png) - -## Available APIs -| API | Description| -| ---------------------------------------------------------------------------------------------- | ----------- | -| register(callback: AsyncCallback\): void | Registers the continuation management service and obtains a token. This API does not involve any filter parameters and uses an asynchronous callback to return the result.| -| register(options: ContinuationExtraParams, callback: AsyncCallback\): void | Registers the continuation management service and obtains a token. This API uses an asynchronous callback to return the result.| -| register(options?: ContinuationExtraParams): Promise\ | Registers the continuation management service and obtains a token. This API uses a promise to return the result.| -| on(type: "deviceConnect", token: number, callback: Callback\>): void | Subscribes to device connection events. This API uses an asynchronous callback to return the result.| -| on(type: "deviceDisconnect", token: number, callback: Callback\>): void | Subscribes to device disconnection events. This API uses an asynchronous callback to return the result.| -| off(type: "deviceConnect", token: number): void | Unsubscribes from device connection events.| -| off(type: "deviceDisconnect", token: number): void | Unsubscribes from device disconnection events.| -| startDeviceManager(token: number, callback: AsyncCallback\): void | Starts the device selection module to show the list of available devices. This API does not involve any filter parameters and uses an asynchronous callback to return the result.| -| startDeviceManager(token: number, options: ContinuationExtraParams, callback: AsyncCallback\): void | Starts the device selection module to show the list of available devices. This API uses an asynchronous callback to return the result.| -| startDeviceManager(token: number, options?: ContinuationExtraParams): Promise\ | Starts the device selection module to show the list of available devices. This API uses a promise to return the result.| -| updateConnectStatus(token: number, deviceId: string, status: DeviceConnectState, callback: AsyncCallback\): void | Instructs the device selection module to update the device connection state. This API uses an asynchronous callback to return the result.| -| updateConnectStatus(token: number, deviceId: string, status: DeviceConnectState): Promise\ | Instructs the device selection module to update the device connection state. This API uses a promise to return the result.| -| unregister(token: number, callback: AsyncCallback\): void | Deregisters the continuation management service. This API uses an asynchronous callback to return the result.| -| unregister(token: number): Promise\ | Deregisters the continuation management service. This API uses a promise to return the result.| - -## How to Develop -1. Import the **continuationManager** module. - - ```ts - import continuationManager from '@ohos.continuation.continuationManager'; - ``` - -2. Apply for permissions required for cross-device continuation or collaboration operations. - - The permission application operation varies according to the ability model in use. In the FA mode, add the required permission in the `config.json` file, as follows: - - ```json - { - "module": { - "reqPermissions": [ - { - "name": "ohos.permission.DISTRIBUTED_DATASYNC" - } - ] - } - } - ``` - - This permission must also be granted by the user through a dialog box when the application is started for the first time. The sample code is as follows: - - ```ts - import abilityAccessCtrl from "@ohos.abilityAccessCtrl"; - import bundle from '@ohos.bundle'; - - async function requestPermission() { - let permissions: Array = [ - "ohos.permission.DISTRIBUTED_DATASYNC" - ]; - let needGrantPermission: boolean = false; - let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); - let applicationInfo = await bundle.getApplicationInfo('ohos.samples.etsDemo', 0, 100); - for (let i = 0; i < permissions.length; i++) { - let result = await atManager.verifyAccessToken(applicationInfo.accessTokenId, permissions[i]); - // Check whether the permission is granted. - if (result == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { - needGrantPermission = true; - break; - } - } - // If the permission is not granted, call requestPermissionsFromUser to apply for the permission. - if (needGrantPermission) { - await featureAbility.getContext().requestPermissionsFromUser(permissions, 1); - } else { - console.info('app permission already granted'); - } - } - ``` - - In the stage model, add the required permission in the `module.json5` file. The sample code is as follows: - - ```json - { - "module": { - "requestPermissions": [ - { - "name": "ohos.permission.DISTRIBUTED_DATASYNC" - } - ] - } - } - ``` - - ```ts - import abilityAccessCtrl from "@ohos.abilityAccessCtrl"; - import bundle from '@ohos.bundle'; - - async function requestPermission() { - let permissions: Array = [ - "ohos.permission.DISTRIBUTED_DATASYNC" - ]; - let needGrantPermission: boolean = false; - let atManger: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); - let applicationInfo = await bundle.getApplicationInfo('ohos.samples.continuationmanager', 0, 100); - for (const permission of permissions) { - try { - let grantStatus = await atManger.verifyAccessToken(applicationInfo.accessTokenId, permission); - // Check whether the permission is granted. - if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) { - needGrantPermission = true; - break; - } - } catch (err) { - console.error('app permission query grant status error' + JSON.stringify(err)); - needGrantPermission = true; - break; - } - } - // If the permission is not granted, call requestPermissionsFromUser to apply for the permission. - if (needGrantPermission) { - try { - await globalThis.abilityContext.requestPermissionsFromUser(permissions); - } catch (err) { - console.error('app permission request permissions error' + JSON.stringify(err)); - } - } else { - console.info('app permission already granted'); - } - } - ``` - -3. Register the continuation management service and obtain a token. - - The sample code is as follows: - - ```ts - let token: number = -1; // Used to save the token returned after the registration. The token will be used when listening for device connection/disconnection events, starting the device selection module, and updating the device connection state. - - continuationManager.register().then((data) => { - console.info('register finished, ' + JSON.stringify(data)); - token = data; // Obtain a token and assign a value to the token variable. - }).catch((err) => { - console.error('register failed, cause: ' + JSON.stringify(err)); - }); - ``` - -4. Listen for the device connection/disconnection state. - - The sample code is as follows: - - ```ts - let remoteDeviceId: string = ""; // Used to save the information about the remote device selected by the user, which will be used for cross-device continuation or collaboration. - - // The token parameter is the token obtained during the registration. - continuationManager.on("deviceConnect", token, (continuationResults) => { - console.info('registerDeviceConnectCallback len: ' + continuationResults.length); - if (continuationResults.length <= 0) { - console.info('no selected device'); - return; - } - remoteDeviceId = continuationResults[0].id; // Assign the deviceId of the first selected remote device to the remoteDeviceId variable. - - // Pass the remoteDeviceId parameter to want. - let want = { - deviceId: remoteDeviceId, - bundleName: 'ohos.samples.continuationmanager', - abilityName: 'MainAbility' - }; - // To initiate multi-device collaboration, you must obtain the ohos.permission.DISTRIBUTED_DATASYNC permission. - globalThis.abilityContext.startAbility(want).then((data) => { - console.info('StartRemoteAbility finished, ' + JSON.stringify(data)); - }).catch((err) => { - console.error('StartRemoteAbility failed, cause: ' + JSON.stringify(err)); - }); - }); - ``` - - The preceding multi-device collaboration operation is performed across devices in the stage model. For details about this operation in the FA model, see [Page Ability Development](https://gitee.com/openharmony/docs/blob/master/en/application-dev/ability/fa-pageability.md). - - You can also instruct the device selection module to update the device connection state. The sample code is as follows: - - ```ts - // Set the device connection state. - let deviceConnectStatus: continuationManager.DeviceConnectState = continuationManager.DeviceConnectState.CONNECTED; - - // The token parameter is the token obtained during the registration, and the remoteDeviceId parameter is the remoteDeviceId obtained. - continuationManager.updateConnectStatus(token, remoteDeviceId, deviceConnectStatus).then((data) => { - console.info('updateConnectStatus finished, ' + JSON.stringify(data)); - }).catch((err) => { - console.error('updateConnectStatus failed, cause: ' + JSON.stringify(err)); - }); - ``` - - Listen for the device disconnection state so that the user can stop cross-device continuation or collaboration in time. The sample code is as follows: - - ```ts - // The token parameter is the token obtained during the registration. - continuationManager.on("deviceDisconnect", token, (deviceIds) => { - console.info('onDeviceDisconnect len: ' + deviceIds.length); - if (deviceIds.length <= 0) { - console.info('no unselected device'); - return; - } - - // Update the device connection state. - let unselectedDeviceId: string = deviceIds[0]; // Assign the deviceId of the first deselected remote device to the unselectedDeviceId variable. - let deviceConnectStatus: continuationManager.DeviceConnectState = continuationManager.DeviceConnectState.DISCONNECTING; // Device disconnected. - - // The token parameter is the token obtained during the registration, and the unselectedDeviceId parameter is the unselectedDeviceId obtained. - continuationManager.updateConnectStatus(token, unselectedDeviceId, deviceConnectStatus).then((data) => { - console.info('updateConnectStatus finished, ' + JSON.stringify(data)); - }).catch((err) => { - console.error('updateConnectStatus failed, cause: ' + JSON.stringify(err)); - }); - }); - ``` - -5. Start the device selection module to show the list of available devices on the network. - - The sample code is as follows: - - ```ts - // Filter parameters. - let continuationExtraParams = { - deviceType: ["00E"], // Device type. - continuationMode: continuationManager.ContinuationMode.COLLABORATION_SINGLE // Single-choice mode of the device selection module. - }; - - // The token parameter is the token obtained during the registration. - continuationManager.startDeviceManager(token, continuationExtraParams).then((data) => { - console.info('startDeviceManager finished, ' + JSON.stringify(data)); - }).catch((err) => { - console.error('startDeviceManager failed, cause: ' + JSON.stringify(err)); - }); - ``` - -6. If you do not need to perform cross-device migration or collaboration operations, you can deregister the continuation management service, by passing the token obtained during the registration. - - The sample code is as follows: - - ```ts - // The token parameter is the token obtained during the registration. - continuationManager.unregister(token).then((data) => { - console.info('unregister finished, ' + JSON.stringify(data)); - }).catch((err) => { - console.error('unregister failed, cause: ' + JSON.stringify(err)); - }); - ``` diff --git a/en/application-dev/ability/fa-brief.md b/en/application-dev/ability/fa-brief.md deleted file mode 100644 index b89c15504376f326629dd2b3dd537e1633d986d0..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/fa-brief.md +++ /dev/null @@ -1,28 +0,0 @@ -# FA Model Overview - -## Overall Architecture -The development of an OpenHarmony application is essentially the development of one or more abilities. By scheduling abilities and managing their lifecycle, OpenHarmony implements application scheduling. - -The Feature Ability (FA) model applies to application development using API version 8 and earlier versions. In this model, there are Page, Service, Data, and Form abilities. -- The Page ability implements the ArkUI and provides the capability of interacting with users. -- The Service ability does not have a UI. It runs in the background and provides custom services for other abilities to invoke. -- The Data ability does not have a UI. It runs in the background and enables other abilities to insert, delete, and query data. -- The Form ability provides a widget, which is a UI display mode. - -## Lifecycle - -Among all abilities, the Page ability has the most complex lifecycle, because it has a UI and acts as a touchpoint for interacting with users. -**The following figure shows the lifecycle of the Page ability.** - -![fa-pageAbility-lifecycle](figures/fa-pageAbility-lifecycle.png) - -The other abilities do not involve the foreground/background switchover and the **onShow** callback. -You can override the lifecycle callbacks in **app.js/app.ets** to process application logic. - -Currently, the **app.js** file provides only the **onCreate** and **onDestroy** callbacks, and the **app.ets** file provides the full lifecycle callbacks. - - -## Process and Thread Model -An application exclusively uses an independent process, and an ability exclusively uses an independent thread. When an ability is started for the first time, an application process as well as a thread for this ability is created. After the application is started, other abilities in the application are started, and a thread is created for every of these started abilities. Each ability is bound to an independent JSRuntime instance. In this way, abilities are isolated from each other. - -![fa-threading-model](figures/fa-threading-model.png) diff --git a/en/application-dev/ability/fa-dataability.md b/en/application-dev/ability/fa-dataability.md deleted file mode 100644 index 36eda5d9210681106a9476bdc87de28f4d06406c..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/fa-dataability.md +++ /dev/null @@ -1,308 +0,0 @@ -# Data Ability Development - -## When to Use - -A Data ability helps applications manage access to data stored by themselves and other applications. It also provides APIs for sharing data with other applications either on the same device or across devices. - -Data ability providers can customize data access-related APIs such as data inserting, deleting, updating, and querying, as well as file opening, and share data with other applications through these open APIs. - -## URI Introduction - -A Uniform Resource Identifier (URI) is used to identify a specific data item, such as a table in the database or a file on the disk. URIs used in OpenHarmony comply with the commonly used URI standard. A URI consists of the components: - -![fa-dataability-uri](figures/fa-dataability-uri.png) - -- **scheme**: name of the scheme used by the Data ability. The value is fixed at **dataability**. -- **authority**: device ID. To access data on a remote device, set this component to the ID of the remote device. To access data on the local device, leave this component empty. -- **path**: location of the specific resource to access. -- **query**: query parameters. -- **fragment**: subordinate resources to access. - -Example URIs: - -- Cross-device communication: **dataability://***device_id***/***com.domainname.dataability.persondata***/***person***/***10* -- Local-device communication: **dataability:///***com.domainname.dataability.persondata***/***person***/***10* - -> **NOTE** -> -> In the case of local-device communication, **device_id** is empty, and therefore, there are three slashes (/) after **dataability:**. - -## Available APIs - -**Table 1** Data ability lifecycle APIs -|API|Description| -|:------|:------| -|onInitialized?(info: AbilityInfo): void|Called during ability initialization to initialize the relational database (RDB).| -|update?(uri: string, valueBucket: rdb.ValuesBucket, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback\): void|Updates data in the database.| -|query?(uri: string, columns: Array\, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback\): void|Queries data in the database.| -|delete?(uri: string, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback\): void|Deletes one or more data records from the database.| -|normalizeUri?(uri: string, callback: AsyncCallback\): void|Normalizes the URI. A normalized URI applies to cross-device use, persistence, backup, and restore. When the context changes, it ensures that the same data item can be referenced.| -|batchInsert?(uri: string, valueBuckets: Array\, callback: AsyncCallback\): void|Inserts multiple data records into the database.| -|denormalizeUri?(uri: string, callback: AsyncCallback\): void|Converts a normalized URI generated by **normalizeUri** into a denormalized URI.| -|insert?(uri: string, valueBucket: rdb.ValuesBucket, callback: AsyncCallback\): void|Inserts a data record into the database.| -|openFile?(uri: string, mode: string, callback: AsyncCallback\): void|Opens a file.| -|getFileTypes?(uri: string, mimeTypeFilter: string, callback: AsyncCallback\>): void|Obtains the MIME type of a file.| -|getType?(uri: string, callback: AsyncCallback\): void|Obtains the MIME type matching the data specified by the URI.| -|executeBatch?(ops: Array\, callback: AsyncCallback\>): void|Operates data in the database in batches.| -|call?(method: string, arg: string, extras: PacMap, callback: AsyncCallback\): void|Calls a custom API.| - - -## How to Develop -### Creating a Data Ability - -1. To meet the basic requirements of the database storage service, implement the **Insert**, **Query**, **Update**, and **Delete** APIs in the **Data** class. The **BatchInsert** and **ExecuteBatch** APIs have already implemented the traversal logic, but not batch data processing. - - The following code snippet shows how to create a Data ability: - - ```javascript - import dataAbility from '@ohos.data.dataAbility' - import dataRdb from '@ohos.data.rdb' - - const TABLE_NAME = 'book' - const STORE_CONFIG = { name: 'book.db' } - const SQL_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS book(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, introduction TEXT NOT NULL)' - let rdbStore: dataRdb.RdbStore = undefined - - export default { - onInitialized(abilityInfo) { - console.info('DataAbility onInitialized, abilityInfo:' + abilityInfo.bundleName) - dataRdb.getRdbStore(STORE_CONFIG, 1, (err, store) => { - console.info('DataAbility getRdbStore callback') - store.executeSql(SQL_CREATE_TABLE, []) - rdbStore = store - }); - }, - insert(uri, valueBucket, callback) { - console.info('DataAbility insert start') - rdbStore.insert(TABLE_NAME, valueBucket, callback) - }, - batchInsert(uri, valueBuckets, callback) { - console.info('DataAbility batch insert start') - for (let i = 0;i < valueBuckets.length; i++) { - console.info('DataAbility batch insert i=' + i) - if (i < valueBuckets.length - 1) { - rdbStore.insert(TABLE_NAME, valueBuckets[i], (err: any, num: number) => { - console.info('DataAbility batch insert ret=' + num) - }) - } else { - rdbStore.insert(TABLE_NAME, valueBuckets[i], callback) - } - } - }, - query(uri, columns, predicates, callback) { - console.info('DataAbility query start') - let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates) - rdbStore.query(rdbPredicates, columns, callback) - }, - update(uri, valueBucket, predicates, callback) { - console.info('DataAbilityupdate start') - let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates) - rdbStore.update(valueBucket, rdbPredicates, callback) - }, - delete(uri, predicates, callback) { - console.info('DataAbilitydelete start') - let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates) - rdbStore.delete(rdbPredicates, callback) - } - }; - ``` - -2. Configure the submodule. - - | JSON Field| Description | - | ------------ | ------------------------------------------------------------ | - | "name" | Ability name, corresponding to the **Data** class name derived from **Ability**. | - | "type" | Ability type, which is **Data** for a Data ability. | - | "uri" | URI used for communication. | - | "visible" | Whether the Data ability is visible to other applications. When this parameter is set to **true**, the Data ability can communicate with other applications.| - - **config.json configuration example** - - ```json - "abilities":[{ - "srcPath": "DataAbility", - "name": ".DataAbility", - "icon": "$media:icon", - "srcLanguage": "ets", - "description": "$string:description_dataability", - "type": "data", - "visible": true, - "uri": "dataability://ohos.samples.etsdataability.DataAbility" - }] - ``` - -### Accessing a Data ability -#### Development Preparations - -Import the basic dependency packages and obtain the URI string for communicating with the Data submodule. - -The basic dependency packages include: -- @ohos.ability.featureAbility -- @ohos.data.dataAbility -- @ohos.data.rdb - -#### Data Ability API Development - - -1. Create a Data ability helper. - - For details about the APIs provided by **DataAbilityHelper**, see [DataAbilityHelper Module](../reference/apis/js-apis-dataAbilityHelper.md). - ```js - // Different from the URI defined in the config.json file, the URI passed in the parameter has an extra slash (/), because there is a DeviceID parameter between the second and the third slash (/). - import featureAbility from '@ohos.ability.featureAbility' - import ohos_data_ability from '@ohos.data.dataAbility' - import ohos_data_rdb from '@ohos.data.rdb' - - var urivar = "dataability:///com.ix.DataAbility" - var DAHelper = featureAbility.acquireDataAbilityHelper( - urivar - ); - ``` -2. Construct RDB data. - ```js - var valuesBucket = {"name": "gaolu"} - var da = new ohos_data_ability.DataAbilityPredicates() - var valArray =new Array("value1"); - var cars = new Array({"batchInsert1" : "value1",}); - ``` -3. Use **insert** to insert data to the Data submodule. - ```js - // Callback mode: - DAHelper.insert( - urivar, - valuesBucket, - (error, data) => { - console.log("DAHelper insert result: " + data) - } - ); - ``` - - ```js - // Promise mode: - var datainsert = await DAHelper.insert( - urivar, - valuesBucket - ); - ``` -4. Use **delete** to delete data from the Data submodule. - ```js - // Callback mode: - DAHelper.delete( - urivar, - da, - (error, data) => { - console.log("DAHelper delete result: " + data) - } - ); - ``` - - ```js - // Promise mode: - var datadelete = await DAHelper.delete( - urivar, - da, - ); - ``` -5. Use **update** to update data in the Data submodule. - ```js - // Callback mode: - DAHelper.update( - urivar - valuesBucket, - da, - (error, data) => { - console.log("DAHelper update result: " + data) - } - ); - ``` - - ```js - // Promise mode: - var dataupdate = await DAHelper.update( - urivar, - valuesBucket, - da, - ); - ``` -6. Use **query** to query data in the Data submodule. - ```js - // Callback mode: - DAHelper.query( - urivar, - valArray, - da, - (error, data) => { - console.log("DAHelper query result: " + data) - } - ); - ``` - - ```js - // Promise mode: - var dataquery = await DAHelper.query( - urivar, - valArray, - da - ); - ``` -7. Use **batchInsert** to insert data in batches to the Data submodule. - ```js - // Callback mode: - DAHelper.batchInsert( - urivar, - cars, - (error, data) => { - console.log("DAHelper batchInsert result: " + data) - } - ); - ``` - - ```js - // Promise mode: - var databatchInsert = await DAHelper.batchInsert( - urivar, - cars - ); - ``` -8. Use **executeBatch** to process data in batches in the Data submodule. - ```js - // Callback mode: - DAHelper.executeBatch( - urivar, - [ - { - uri: urivar, - type: featureAbility.DataAbilityOperationType.TYPE_INSERT, - valuesBucket: {"executeBatch" : "value1",}, - predicates: da, - expectedCount:0, - predicatesBackReferences: null, - interrupted:true, - } - ], - (error, data) => { - console.log("DAHelper executeBatch result: " + data) - } - ); - ``` - - ```js - // Promise mode: - var dataexecuteBatch = await DAHelper.executeBatch( - urivar, - [ - { - uri: urivar, - type: featureAbility.DataAbilityOperationType.TYPE_INSERT, - valuesBucket: - { - "executeBatch" : "value1", - }, - predicates: da, - expectedCount:0, - predicatesBackReferences: null, - interrupted:true, - } - ] - ); - ``` diff --git a/en/application-dev/ability/fa-formability.md b/en/application-dev/ability/fa-formability.md deleted file mode 100644 index c1cadebe652dbd9f195e96ed1dec221df0eff849..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/fa-formability.md +++ /dev/null @@ -1,404 +0,0 @@ -# FA Widget Development - -## Widget Overview -A widget is a set of UI components used to display important information or operations for an application. It provides users with direct access to a desired application service, without requiring them to open the application. - -A widget displays brief information about an application on the UI of another application (host application, currently system applications only) and provides basic interactive functions such as opening a UI page or sending a message. - -Basic concepts: -- Widget provider: an atomic service that controls what and how content is displayed in a widget and interacts with users. -- Widget host: an application that displays the widget content and controls the position where the widget is displayed in the host application. -- Widget Manager: a resident agent that manages widgets added to the system and provides functions such as periodic widget update. - -> **NOTE** -> -> The widget host and provider do not keep running all the time. The Widget Manager starts the widget provider to obtain widget information when a widget is added, deleted, or updated. - -You only need to develop widget content as the widget provider. The system automatically handles the work done by the widget host and Widget Manager. - -The widget provider controls the widget content to display, component layout, and click events bound to components. - -## Development Overview - -In FA widget development, you need to carry out the following operations as a widget provider based on the [Feature Ability (FA) model](fa-brief.md). - -- Develop the lifecycle callbacks in **LifecycleForm**. -- Create a **FormBindingData** instance. -- Update a widget through **FormProvider**. -- Develop the widget UI pages. - -## Available APIs - -The table below describes the lifecycle callbacks provided in **LifecycleForm**. - -**Table 1** LifecycleForm APIs - -| API | Description | -| :----------------------------------------------------------- | :------------------------------------------- | -| onCreate(want: Want): formBindingData.FormBindingData | Called to notify the widget provider that a **Form** instance (widget) has been created. | -| onCastToNormal(formId: string): void | Called to notify the widget provider that a temporary widget has been converted to a normal one.| -| onUpdate(formId: string): void | Called to notify the widget provider that a widget has been updated. | -| onVisibilityChange(newStatus: { [key: string]: number }): void | Called to notify the widget provider of the change in widget visibility. | -| onEvent(formId: string, message: string): void | Called to instruct the widget provider to receive and process a widget event. | -| onDestroy(formId: string): void | Called to notify the widget provider that a **Form** instance (widget) has been destroyed. | -| onAcquireFormState?(want: Want): formInfo.FormState | Called when the widget provider receives the status query result of a widget. | - -For details about the **FormProvider** APIs, see [FormProvider](../reference/apis/js-apis-formprovider.md). - -**Table 2** FormProvider APIs - -| API | Description | -| :----------------------------------------------------------- | :------------------------------------------------ | -| setFormNextRefreshTime(formId: string, minute: number, callback: AsyncCallback<void>): void; | Sets the next refresh time for a widget. This API uses an asynchronous callback to return the result. | -| setFormNextRefreshTime(formId: string, minute: number): Promise<void>; | Sets the next refresh time for a widget. This API uses a promise to return the result.| -| updateForm(formId: string, formBindingData: FormBindingData, callback: AsyncCallback<void>): void; | Updates a widget. This API uses an asynchronous callback to return the result. | -| updateForm(formId: string, formBindingData: FormBindingData): Promise<void>; | Updates a widget. This API uses a promise to return the result. | - -## How to Develop - -### Creating LifecycleForm - -To create a widget in the FA model, you need to implement the lifecycles of **LifecycleForm**. The sample code is as follows: - -1. Import the required modules. - - ```javascript - import formBindingData from '@ohos.application.formBindingData' - import formInfo from '@ohos.application.formInfo' - import formProvider from '@ohos.application.formProvider' - ``` - -2. Implement the lifecycle callbacks of **LifecycleForm**. - - ```javascript - export default { - onCreate(want) { - console.log('FormAbility onCreate'); - // Persistently store widget information for subsequent use, such as widget instance retrieval or update. - let obj = { - "title": "titleOnCreate", - "detail": "detailOnCreate" - }; - let formData = formBindingData.createFormBindingData(obj); - return formData; - }, - onCastToNormal(formId) { - // Called when the widget host converts the temporary widget into a normal one. The widget provider should do something to respond to the conversion. - console.log('FormAbility onCastToNormal'); - }, - onUpdate(formId) { - // To support scheduled update, periodic update, or update requested by the widget host, override this method for widget data update. - console.log('FormAbility onUpdate'); - let obj = { - "title": "titleOnUpdate", - "detail": "detailOnUpdate" - }; - let formData = formBindingData.createFormBindingData(obj); - formProvider.updateForm(formId, formData).catch((error) => { - console.log('FormAbility updateForm, error:' + JSON.stringify(error)); - }); - }, - onVisibilityChange(newStatus) { - // Called when the widget host initiates an event about visibility changes. The widget provider should do something to respond to the notification. - console.log('FormAbility onVisibilityChange'); - }, - onEvent(formId, message) { - // If the widget supports event triggering, override this method and implement the trigger. - console.log('FormAbility onEvent'); - }, - onDestroy(formId) { - // Delete widget data. - console.log('FormAbility onDestroy'); - }, - onAcquireFormState(want) { - console.log('FormAbility onAcquireFormState'); - return formInfo.FormState.READY; - }, - } - ``` - -### Configuring the Widget Configuration File - -Configure the **config.json** file for the widget. - -- The **js** module in the **config.json** file provides the JavaScript resources of the widget. The internal structure is described as follows: - - | Field| Description | Data Type| Default | - | -------- | ------------------------------------------------------------ | -------- | ------------------------ | - | name | Name of a JavaScript component. The default value is **default**. | String | No | - | pages | Route information about all pages in the JavaScript component, including the page path and page name. The value is an array, in which each element represents a page. The first element in the array represents the home page of the JavaScript FA.| Array | No | - | window | Window-related configurations. | Object | Yes | - | type | Type of the JavaScript component. Available values are as follows:
**normal**: indicates that the JavaScript component is an application instance.
**form**: indicates that the JavaScript component is a widget instance.| String | Yes (initial value: **normal**)| - | mode | Development mode of the JavaScript component. | Object | Yes (initial value: left empty) | - - A configuration example is as follows: - - ```json - "js": [{ - "name": "widget", - "pages": ["pages/index/index"], - "window": { - "designWidth": 720, - "autoDesignWidth": true - }, - "type": "form" - }] - ``` - -- The **abilities** module in the **config.json** file corresponds to the **LifecycleForm** of the widget. The internal structure is described as follows: - - | Field | Description | Data Type | Default | - | ------------------- | ------------------------------------------------------------ | ---------- | ------------------------ | - | name | Class name of the widget. The value is a string with a maximum of 127 bytes. | String | No | - | description | Description of the widget. The value can be a string or a resource index to descriptions in multiple languages. The value is a string with a maximum of 255 bytes.| String | Yes (initial value: left empty) | - | isDefault | Whether the widget is a default one. Each ability has only one default widget.
**true**: The widget is the default one.
**false**: The widget is not the default one.| Boolean | No | - | type | Type of the widget. Available values are as follows:
**JS**: indicates a JavaScript-programmed widget. | String | No | - | colorMode | Color mode of the widget. Available values are as follows:
**auto**: The widget adopts the auto-adaptive color mode.
**dark**: The widget adopts the dark color mode.
**light**: The widget adopts the light color mode.| String | Yes (initial value: **auto**)| - | supportDimensions | Grid styles supported by the widget. Available values are as follows:
**1 * 2**: indicates a grid with one row and two columns.
**2 * 2**: indicates a grid with two rows and two columns.
**2 * 4**: indicates a grid with two rows and four columns.
**4 * 4**: indicates a grid with four rows and four columns.| String array| No | - | defaultDimension | Default grid style of the widget. The value must be available in the **supportDimensions** array of the widget.| String | No | - | updateEnabled | Whether the widget can be updated periodically. Available values are as follows:
**true**: The widget can be updated periodically, depending on the update way you select, either at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** is preferentially recommended.
**false**: The widget cannot be updated periodically.| Boolean | No | - | scheduledUpdateTime | Scheduled time to update the widget. The value is in 24-hour format and accurate to minute.
This parameter has a lower priority than **updateDuration**. If both are specified, the value specified by **updateDuration** is used.| String | Yes (initial value: **0:0**) | - | updateDuration | Interval to update the widget. The value is a natural number, in the unit of 30 minutes.
If the value is **0**, this field does not take effect.
If the value is a positive integer ***N***, the interval is calculated by multiplying ***N*** and 30 minutes.
This parameter has a higher priority than **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| Number | Yes (initial value: **0**) | - | formConfigAbility | Link to a specific page of the application. The value is a URI. | String | Yes (initial value: left empty) | - | formVisibleNotify | Whether the widget is allowed to use the widget visibility notification. | String | Yes (initial value: left empty) | - | jsComponentName | Component name of the widget. The value is a string with a maximum of 127 bytes. | String | No | - | metaData | Metadata of the widget. This field contains the array of the **customizeData** field. | Object | Yes (initial value: left empty) | - | customizeData | Custom information about the widget. | Object array | Yes (initial value: left empty) | - - A configuration example is as follows: - - ```json - "abilities": [{ - "name": "FormAbility", - "description": "This is a FormAbility", - "formsEnabled": true, - "icon": "$media:icon", - "label": "$string:form_FormAbility_label", - "srcPath": "FormAbility", - "type": "service", - "srcLanguage": "ets", - "formsEnabled": true, - "forms": [{ - "colorMode": "auto", - "defaultDimension": "2*2", - "description": "This is a widget.", - "formVisibleNotify": true, - "isDefault": true, - "jsComponentName": "widget", - "name": "widget", - "scheduledUpdateTime": "10:30", - "supportDimensions": ["2*2"], - "type": "JS", - "updateEnabled": true - }] - }] - ``` - - -### Persistently Storing Widget Data - -Mostly, the widget provider is started only when it needs to obtain information about a widget. The Widget Manager supports multi-instance management and uses the widget ID to identify an instance. If the widget provider supports widget data modification, it must persistently store the data based on the widget ID, so that it can access the data of the target widget when obtaining, updating, or starting a widget. - -```javascript - onCreate(want) { - console.log('FormAbility onCreate'); - - let formId = want.parameters["ohos.extra.param.key.form_identity"]; - let formName = want.parameters["ohos.extra.param.key.form_name"]; - let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"]; - // Persistently store widget information for subsequent use, such as widget instance retrieval or update. - // The storeFormInfo API is not implemented here. - storeFormInfo(formId, formName, tempFlag, want); - - let obj = { - "title": "titleOnCreate", - "detail": "detailOnCreate" - }; - let formData = formBindingData.createFormBindingData(obj); - return formData; - } -``` - -You should override **onDestroy** to delete widget data. - -```javascript - onDestroy(formId) { - console.log('FormAbility onDestroy'); - - // You need to implement the code for deleting the persistent widget instance. - // The deleteFormInfo API is not implemented here. - deleteFormInfo(formId); - } -``` - -For details about the persistence method, see [Lightweight Data Store Development](../database/database-preference-guidelines.md). - -Note that the **Want** passed by the widget host to the widget provider contains a flag that indicates whether the requested widget is a temporary one. - -- Normal widget: a widget that will be persistently used by the widget host - -- Temporary widget: a widget that is temporarily used by the widget host - -Data of a temporary widget is not persistently stored. If the widget framework is killed and restarted, data of a temporary widget will be deleted. However, the widget provider is not notified of which widget is deleted, and still keeps the data. Therefore, the widget provider should implement data clearing. In addition, the widget host may convert a temporary widget into a normal one. If the conversion is successful, the widget provider should process the widget ID and store the data persistently. This prevents the widget provider from deleting persistent data when clearing temporary widgets. - -### Updating Widget Data - -When a widget application initiates a data update upon a scheduled or periodic update, the application obtains the latest data and calls **updateForm** to update the widget. The code snippet is as follows: - -```javascript -onUpdate(formId) { - // To support scheduled update, periodic update, or update requested by the widget host, override this method for widget data update. - console.log('FormAbility onUpdate'); - let obj = { - "title": "titleOnUpdate", - "detail": "detailOnUpdate" - }; - let formData = formBindingData.createFormBindingData(obj); - // Call the updateForm method to update the widget. Only the data passed through the input parameter is updated. Other information remains unchanged. - formProvider.updateForm(formId, formData).catch((error) => { - console.log('FormAbility updateForm, error:' + JSON.stringify(error)); - }); -} -``` - -### Developing Widget UI Pages - -You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programmed widget. - -> **NOTE** -> -> Currently, only the JavaScript-based web-like development paradigm can be used to develop the widget UI. - - - In the HML file: - ```html -
- -
- -
-
- {{title}} - {{detail}} -
-
-
- ``` - - - In the CSS file: - - ```css -.container { - flex-direction: column; - justify-content: center; - align-items: center; -} - -.bg-img { - flex-shrink: 0; - height: 100%; -} - -.container-inner { - flex-direction: column; - justify-content: flex-end; - align-items: flex-start; - height: 100%; - width: 100%; - padding: 12px; -} - -.title { - font-size: 19px; - font-weight: bold; - color: white; - text-overflow: ellipsis; - max-lines: 1; -} - -.detail_text { - font-size: 16px; - color: white; - opacity: 0.66; - text-overflow: ellipsis; - max-lines: 1; - margin-top: 6px; -} - ``` - - - In the JSON file: - ```json - { - "data": { - "title": "TitleDefault", - "detail": "TextDefault" - }, - "actions": { - "routerEvent": { - "action": "router", - "abilityName": "com.example.entry.MainAbility", - "params": { - "message": "add detail" - } - } - } - } - ``` - -Now you've got a widget shown below. - -![fa-form-example](figures/fa-form-example.png) - -### Developing Widget Events - -You can set router and message events for components on a widget. The router event applies to ability redirection, and the message event applies to custom click events. The key steps are as follows: - -1. Set **onclick** in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file. -2. For the router event, set the following attributes: - - **action**: **"router"**. - - **abilityName**: target ability name, for example, **com.example.entry.MainAbility**, which is the default main ability name in DevEco Studio for the FA model. - - **params**: custom parameters of the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the main ability in the FA model, **featureAbility.getWant()** can be used to obtain **want** and its **parameters** field. -3. For the message event, set the following attributes: - - **action**: **"message"**. - - **params**: custom parameters of the message event. Set them as required. The value can be obtained from **message** in the widget lifecycle function **onEvent**. - -The code snippet is as follows: - - - In the HML file: - ```html -
- -
- -
-
- {{title}} - {{detail}} -
-
-
- ``` - - - In the JSON file: - ```json - { - "data": { - "title": "TitleDefault", - "detail": "TextDefault" - }, - "actions": { - "routerEvent": { - "action": "router", - "abilityName": "com.example.entry.MainAbility", - "params": { - "message": "add detail" - } - }, - "messageEvent": { - "action": "message", - "params": { - "message": "add detail" - } - } - } - } - ``` \ No newline at end of file diff --git a/en/application-dev/ability/fa-pageability.md b/en/application-dev/ability/fa-pageability.md deleted file mode 100644 index 3a2629a79996660f48dfc247b9a560ea1abe09b4..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/fa-pageability.md +++ /dev/null @@ -1,219 +0,0 @@ -# Page Ability Development - -## Overview -### Concepts -The Page ability implements the ArkUI and provides the capability of interacting with developers. When you create an ability in DevEco Studio, DevEco Studio automatically creates template code. The capabilities related to the Page ability are implemented through the **featureAbility**, and the lifecycle callbacks are implemented through the callbacks in **app.js** or **app.ets**. - -### Page Ability Lifecycle - -**Ability lifecycle** - -The Page ability lifecycle defines all states of a Page ability, such as **INACTIVE**, **ACTIVE**, and **BACKGROUND**. - -The following figure shows the lifecycle state transition of the Page ability. - -![PageAbility-Lifecycle](figures/page-ability-lifecycle.png) - - -Description of ability lifecycle states: - - - **UNINITIALIZED**: The Page ability is not initialized. This is a temporary state, from which a Page ability changes directly to the **INITIAL** state upon its creation. - - - **INITIAL**: The Page ability is initialized but not running. The Page ability enters the **INACTIVE** state after it is started. - - - **INACTIVE**: The Page ability is visible but does not gain focus. - - - **ACTIVE**: The Page ability runs in the foreground and has focus. - - - **BACKGROUND**: The Page ability runs in the background. After being re-activated, the Page ability enters the **ACTIVE** state. After being destroyed, the Page ability enters the **INITIAL** state. - -**The following figure shows the relationship between lifecycle callbacks and lifecycle states of the Page ability.** - -![fa-pageAbility-lifecycle](figures/fa-pageAbility-lifecycle.png) - -You can override the lifecycle callbacks provided by the Page ability in the **app.js** or **app.ets** file. Currently, the **app.js** file provides only the **onCreate** and **onDestroy** callbacks, and the **app.ets** file provides the full lifecycle callbacks. - -### Launch Type -The ability supports two launch types: singleton and multi-instance. -You can specify the launch type by setting **launchType** in the **config.json** file. - -**Table 1** Introduction to startup mode - -| Launch Type | Description |Description | -| ----------- | ------- |---------------- | -| standard | Multi-instance | A new instance is started each time an ability starts.| -| singleton | Singleton | Only one instance exists in the system. If an instance already exists when an ability is started, that instance is reused.| - -By default, **singleton** is used. - - -## Development Guidelines -### Available APIs - -**Table 2** APIs provided by featureAbility - -| API | Description | -| --------------------------------------------------- | --------------- | -| void startAbility(parameter: StartAbilityParameter) | Starts an ability. | -| Context getContext(): | Obtains the application context.| -| void terminateSelf() | Terminates the ability. | -| bool hasWindowFocus() | Checks whether the ability has focus. | - - -### Starting a Local Page Ability - -**Modules to Import** - -```js - import featureAbility from '@ohos.ability.featureAbility' -``` - -**Example** - -```javascript - import featureAbility from '@ohos.ability.featureAbility' - featureAbility.startAbility({ - want: - { - action: "", - entities: [""], - type: "", - deviceId: "", - bundleName: "com.example.myapplication", - /* In the FA model, abilityName consists of package and ability name. */ - abilityName: "com.example.entry.secondAbility", - uri: "" - }, - }, - ); -``` - -### Starting a Remote Page Ability ->Note -> ->This feature applies only to system applications, since the **getTrustedDeviceListSync** API of the **DeviceManager** class is open only to system applications. - -**Modules to Import** - -``` - import featureAbility from '@ohos.ability.featureAbility' - import deviceManager from '@ohos.distributedHardware.deviceManager'; -``` - -**Example** -```ts - function onStartRemoteAbility() { - console.info('onStartRemoteAbility begin'); - let params; - let wantValue = { - bundleName: 'ohos.samples.etsDemo', - abilityName: 'ohos.samples.etsDemo.RemoteAbility', - deviceId: getRemoteDeviceId(), - parameters: params - }; - console.info('onStartRemoteAbility want=' + JSON.stringify(wantValue)); - featureAbility.startAbility({ - want: wantValue - }).then((data) => { - console.info('onStartRemoteAbility finished, ' + JSON.stringify(data)); - }); - console.info('onStartRemoteAbility end'); - } -``` - -Obtain **deviceId** from **DeviceManager**. The sample code is as follows: - -```ts - import deviceManager from '@ohos.distributedHardware.deviceManager'; - let dmClass; - function getRemoteDeviceId() { - if (typeof dmClass === 'object' && dmClass != null) { - let list = dmClass.getTrustedDeviceListSync(); - if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { - console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null"); - return; - } - console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId); - return list[0].deviceId; - } else { - console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null"); - } - } -``` - -In the cross-device scenario, the application must also apply for the data synchronization permission from end users. The sample code is as follows: - -```ts - import abilityAccessCtrl from "@ohos.abilityAccessCtrl"; - import bundle from '@ohos.bundle'; - async function RequestPermission() { - console.info('RequestPermission begin'); - let array: Array = ["ohos.permission.DISTRIBUTED_DATASYNC"]; - let bundleFlag = 0; - let tokenID = undefined; - let userID = 100; - let appInfo = await bundle.getApplicationInfo('ohos.samples.etsDemo', bundleFlag, userID); - tokenID = appInfo.accessTokenId; - let atManager = abilityAccessCtrl.createAtManager(); - let requestPermissions: Array = []; - for (let i = 0;i < array.length; i++) { - let result = await atManager.verifyAccessToken(tokenID, array[i]); - console.info("verifyAccessToken result:" + JSON.stringify(result)); - if (result != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { - requestPermissions.push(array[i]); - } - } - console.info("requestPermissions:" + JSON.stringify(requestPermissions)); - if (requestPermissions.length == 0 || requestPermissions == []) { - return; - } - let context = featureAbility.getContext(); - context.requestPermissionsFromUser(requestPermissions, 1, (data)=>{ - console.info("data:" + JSON.stringify(data)); - console.info("data requestCode:" + data.requestCode); - console.info("data permissions:" + data.permissions); - console.info("data authResults:" + data.authResults); - }); - console.info('RequestPermission end'); - } -``` - -### Lifecycle APIs - -**Table 3** Lifecycle callbacks - -| API | Description | -| ------------ | ------------------------------------------------------------ | -| onShow() | Called when the ability is switched from the background to the foreground. In this case, the ability is visible to users.| -| onHide() | Called when the ability is switched from the foreground to the background. In this case, the ability is invisible to users.| -| onDestroy() | Called when the ability is destroyed. In this callback, you can make preparations for application exit, such as recycling resources and clearing the cache.| -| onCreate() | Called when the ability is created for the first time. You can initialize the application in this callback.| -| onInactive() | Called when the ability loses focus. An ability loses focus when it is about to enter the background state.| -| onActive() | Called when the ability is switched to the foreground and gains focus. | - -**Example** - -You need to override the lifecycle callbacks except **onCreate()** and **onDestroy()** in **app.js** or **app.ets**. The **onCreate()** and **onDestroy()** callbacks are automatically generated in the template code provided by DevEco Studio. - -```javascript -export default { - onCreate() { - console.info('Application onCreate') - }, - onDestroy() { - console.info('Application onDestroy') - }, - onShow(){ - console.info('Application onShow') - }, - onHide(){ - console.info('Application onHide') - }, - onInactive(){ - console.info('Application onInactive') - }, - onActive(){ - console.info('Application onActive') - }, -} -``` diff --git a/en/application-dev/ability/fa-serviceability.md b/en/application-dev/ability/fa-serviceability.md deleted file mode 100644 index 48270359d9d49f9ea7d7111b021cd8b81da3df82..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/fa-serviceability.md +++ /dev/null @@ -1,400 +0,0 @@ -# Service Ability Development - -## When to Use -A Service ability is used to run tasks in the background, such as playing music or downloading files. It does not provide a UI for user interaction. Service abilities can be started by other applications or abilities and can remain running in the background even after the user switches to another application. - -## Available APIs - -**Table 1** Service ability lifecycle APIs -|API|Description| -|:------|:------| -|onStart?(): void|Called to initialize a Service ability being created. This callback is invoked only once in the entire lifecycle of a Service ability. The **Want** object passed to this callback must be null.| -|onCommand?(want: Want, startId: number): void|Called every time a Service ability is created on a client. You can collect calling statistics and perform initialization operations in this callback.| -|onConnect?(want: Want): rpc.RemoteObject|Called when another ability is connected to the Service ability.| -|onDisconnect?(want: Want): void|Called when another ability is disconnected from the Service ability.| -|onStop?(): void|Called when the Service ability is being destroyed. You should override this callback for your Service ability to clear its resources, such as threads and registered listeners.| - -## How to Develop - -### Creating and Registering a Service Ability - -1. Override the Service ability-related lifecycle callbacks to implement your own logic for processing interaction requests. - - ```javascript - export default { - onStart() { - console.log('ServiceAbility onStart'); - }, - onCommand(want, startId) { - console.log('ServiceAbility onCommand'); - }, - onConnect(want) { - console.log('ServiceAbility OnConnect'); - return new FirstServiceAbilityStub('test'); - }, - onDisconnect(want) { - console.log('ServiceAbility OnDisConnect'); - }, - onStop() { - console.log('ServiceAbility onStop'); - }, - } - ``` - -2. Register a Service ability. - - Declare the Service ability in the **config.json** file by setting its **type** attribute to **service**. - - ```javascript - { - "module": { - "abilities": [ - { - "name": ".ServiceAbility", - "type": "service", - "visible": true - ... - } - ] - ... - } - ... - } - ``` - - - -### Starting a Service Ability - -The **Ability** class provides the **startAbility()** API for you to start another Service ability by passing a **Want** object. - -To set information about the target Service ability, you can first construct a **Want** object with the **bundleName** and **abilityName** parameters specified. The meanings of the parameters are as follows: - -- **bundleName** indicates the name of the bundle to which the target ability belongs. -- **abilityName** indicates the target ability name. - -The following code snippet shows how to start a Service ability running on the local device: - -```javascript -import featureAbility from '@ohos.ability.featureAbility'; -let promise = featureAbility.startAbility( - { - want: - { - bundleName: "com.jstest.service", - abilityName: "com.jstest.service.ServiceAbility", - }, - } -); -``` - -After the preceding code is executed, the **startAbility()** API is called to start the Service ability. -- If the Service ability is not running, the system calls **onStart()** to initialize the Service ability, and then calls **onCommand()** on the Service ability. -- If the Service ability is running, the system directly calls **onCommand()** on the Service ability. - -The following code snippet shows how to start a Service ability running on the remote device. For details about **getRemoteDeviceId()**, see [Connecting to a Remote Service Ability](#connecting-to-a-remote-service-ability-applying-only-to-system-applications). - -```javascript -import featureAbility from '@ohos.ability.featureAbility'; -let promise = featureAbility.startAbility( - { - want: - { - deviceId: getRemoteDeviceId(), // Remote device ID - bundleName: "com.jstest.service", - abilityName: "com.jstest.service.ServiceAbility", - }, - } -); -``` - - -### Stopping a Service Ability - -Once created, the Service ability keeps running in the background. The system does not stop or destroy it unless memory resources must be reclaimed. - -### Connecting to a Local Service Ability - -If you need to connect a Service ability to a Page ability or to a Service ability in another application, you must first implement the **IAbilityConnection** API for the connection. A Service ability allows other abilities to connect to it through **connectAbility()**. - - -You can use either of the following methods to connect to a Service ability: - -1. Using the IDL to automatically generate code - - Use OpenHarmony Interface Definition Language (IDL) to automatically generate the corresponding client, server, and **IRemoteObject** code. For details, see “Development Using TS" in [OpenHarmony IDL Specifications and User Guide](../IDL/idl-guidelines.md). - -2. Writing code in the corresponding file - - When calling **connectAbility()**, you should pass a **Want** object containing information about the target Service ability and an **IAbilityConnection** object to the API. **IAbilityConnection** provides the following callbacks that you should implement: **onConnect()**, **onDisconnect()**, and **onFailed()**. The **onConnect()** callback is invoked when a Service ability is connected, **onDisconnect()** is invoked when a Service ability is unexpectedly disconnected, and **onFailed()** is invoked when a connection to a Service ability fails. - - The following code snippet shows how to implement the callbacks: - - ```javascript - import prompt from '@system.prompt' - - var option = { - onConnect: function onConnectCallback(element, proxy) { - console.log(`onConnectLocalService onConnectDone`) - if (proxy === null) { - prompt.showToast({ - message: "Connect service failed" - }) - return - } - let data = rpc.MessageParcel.create() - let reply = rpc.MessageParcel.create() - let option = new rpc.MessageOption() - data.writeInterfaceToken("connect.test.token") - proxy.sendRequest(0, data, reply, option) - prompt.showToast({ - message: "Connect service success" - }) - }, - onDisconnect: function onDisconnectCallback(element) { - console.log(`onConnectLocalService onDisconnectDone element:${element}`) - prompt.showToast({ - message: "Disconnect service success" - }) - }, - onFailed: function onFailedCallback(code) { - console.log(`onConnectLocalService onFailed errCode:${code}`) - prompt.showToast({ - message: "Connect local service onFailed" - }) - } - } - ``` - - The following code snippet shows how to connect to a local Service ability: - - ```javascript - import featureAbility from '@ohos.ability.featureAbility'; - let connId = featureAbility.connectAbility( - { - bundleName: "com.jstest.service", - abilityName: "com.jstest.service.ServiceAbility", - }, - { - onConnect: onConnectCallback, - onDisconnect: onDisconnectCallback, - onFailed: onFailedCallback, - }, - ); - ``` - - When a Service ability is connected, the **onConnect()** callback is invoked and returns an **IRemoteObject** defining the proxy used for communicating with the Service ability. OpenHarmony provides a default implementation of **IRemoteObject**. You can extend **rpc.RemoteObject** to implement your own class of **IRemoteObject**. - - The following code snippet shows how the Service ability instance returns itself to the calling ability: - - ```javascript - import rpc from "@ohos.rpc"; - - class FirstServiceAbilityStub extends rpc.RemoteObject { - constructor(des: any) { - if (typeof des === 'string') { - super(des) - } else { - return - } - } - - onRemoteRequest(code: number, data: any, reply: any, option: any) { - console.log(printLog + ` onRemoteRequest called`) - if (code === 1) { - let string = data.readString() - console.log(printLog + ` string=${string}`) - let result = Array.from(string).sort().join('') - console.log(printLog + ` result=${result}`) - reply.writeString(result) - } else { - console.log(printLog + ` unknown request code`) - } - return true; - } - ``` - -### Connecting to a Remote Service Ability - ->**NOTE** -> ->This feature applies only to system applications, since the **getTrustedDeviceListSync** API of the **DeviceManager** class is open only to system applications. - -If you need to connect a Service ability to a Page ability or another Service ability on a remote device, you must first implement the **IAbilityConnection** interface for the connection. A Service ability allows abilities on another device to connect to it through **connectAbility()**. - -When calling **connectAbility()**, you should pass a **Want** object containing information about the target Service ability and an **IAbilityConnection** object to the API. **IAbilityConnection** provides the following callbacks that you should implement: **onConnect()**, **onDisconnect()**, and **onFailed()**. The **onConnect()** callback is invoked when a Service ability is connected, **onDisconnect()** is invoked when a Service ability is unexpectedly disconnected, and **onFailed()** is invoked when a connection to a Service ability fails. - -The following code snippet shows how to implement the callbacks: - -```ts -import prompt from '@system.prompt' - -var option = { - onConnect: function onConnectCallback(element, proxy) { - console.log(`onConnectRemoteService onConnectDone`) - if (proxy === null) { - prompt.showToast({ - message: "Connect service failed" - }) - return - } - let data = rpc.MessageParcel.create() - let reply = rpc.MessageParcel.create() - let option = new rpc.MessageOption() - data.writeInterfaceToken("connect.test.token") - proxy.sendRequest(0, data, reply, option) - prompt.showToast({ - message: "Connect service success" - }) - }, - onDisconnect: function onDisconnectCallback(element) { - console.log(`onConnectRemoteService onDisconnectDone element:${element}`) - prompt.showToast({ - message: "Disconnect service success" - }) - }, - onFailed: function onFailedCallback(code) { - console.log(`onConnectRemoteService onFailed errCode:${code}`) - prompt.showToast({ - message: "Connect local service onFailed" - }) - } -} -``` - -The **Want** of the target Service ability must contain the remote **deviceId**, which can be obtained from **DeviceManager**. The sample code is as follows: - -```ts -import deviceManager from '@ohos.distributedHardware.deviceManager'; - -// For details about the implementation of dmClass, see the implementation in Distributed Demo in Samples. -let dmClass; - -function getRemoteDeviceId() { - if (typeof dmClass === 'object' && dmClass != null) { - let list = dmClass.getTrustedDeviceListSync(); - if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { - console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null"); - return; - } - console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId); - return list[0].deviceId; - } else { - console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null"); - } -} -``` - -The following code snippet shows how to connect to a remote Service ability: - -```ts -import featureAbility from '@ohos.ability.featureAbility'; -let connId = featureAbility.connectAbility( - { - deviceId: getRemoteDeviceId(), - bundleName: "ohos.samples.etsDemo", - abilityName: "ohos.samples.etsDemo.ServiceAbility", - }, - { - onConnect: onConnectCallback, - onDisconnect: onDisconnectCallback, - onFailed: onFailedCallback, - }, -); -``` -In the cross-device scenario, the application must also apply for the data synchronization permission from end users. The sample code is as follows: - -```ts -import abilityAccessCtrl from "@ohos.abilityAccessCtrl"; -import bundle from '@ohos.bundle'; -async function RequestPermission() { - console.info('RequestPermission begin'); - let array: Array = ["ohos.permission.DISTRIBUTED_DATASYNC"]; - let bundleFlag = 0; - let tokenID = undefined; - let userID = 100; - let appInfo = await bundle.getApplicationInfo('ohos.samples.etsDemo', bundleFlag, userID); - tokenID = appInfo.accessTokenId; - let atManager = abilityAccessCtrl.createAtManager(); - let requestPermissions: Array = []; - for (let i = 0;i < array.length; i++) { - let result = await atManager.verifyAccessToken(tokenID, array[i]); - console.info("verifyAccessToken result:" + JSON.stringify(result)); - if (result == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { - } else { - requestPermissions.push(array[i]); - } - } - console.info("requestPermissions:" + JSON.stringify(requestPermissions)); - if (requestPermissions.length == 0 || requestPermissions == []) { - return; - } - let context = featureAbility.getContext(); - context.requestPermissionsFromUser(requestPermissions, 1, (data)=>{ - console.info("data:" + JSON.stringify(data)); - }); - console.info('RequestPermission end'); -} -``` - -When a Service ability is connected, the **onConnect()** callback is invoked and returns an **IRemoteObject** defining the proxy used for communicating with the Service ability. OpenHarmony provides a default implementation of **IRemoteObject**. You can extend **rpc.RemoteObject** to implement your own class of **IRemoteObject**. - -The following code snippet shows how the Service ability instance returns itself to the calling ability: - -```ts -import rpc from "@ohos.rpc"; - -class FirstServiceAbilityStub extends rpc.RemoteObject { - constructor(des: any) { - if (typeof des === 'string') { - super(des) - } else { - return - } - } - - onRemoteRequest(code: number, data: any, reply: any, option: any) { - console.log(printLog + ` onRemoteRequest called`) - if (code === 1) { - let string = data.readString() - console.log(printLog + ` string=${string}`) - let result = Array.from(string).sort().join('') - console.log(printLog + ` result=${result}`) - reply.writeString(result) - } else { - console.log(printLog + ` unknown request code`) - } - return true; - } -} - -export default { - onStart() { - console.info('ServiceAbility onStart'); - }, - onStop() { - console.info('ServiceAbility onStop'); - }, - onConnect(want) { - console.log("ServiceAbility onConnect"); - try { - let value = JSON.stringify(want); - console.log("ServiceAbility want:" + value); - } catch(error) { - console.log("ServiceAbility error:" + error); - } - return new FirstServiceAbilityStub("first ts service stub"); - }, - onDisconnect(want) { - console.log("ServiceAbility onDisconnect"); - let value = JSON.stringify(want); - console.log("ServiceAbility want:" + value); - }, - onCommand(want, startId) { - console.info('ServiceAbility onCommand'); - let value = JSON.stringify(want); - console.log("ServiceAbility want:" + value); - console.log("ServiceAbility startId:" + startId); - } -}; -``` diff --git a/en/application-dev/ability/figures/contextIntroduction.png b/en/application-dev/ability/figures/contextIntroduction.png deleted file mode 100644 index 7345a1a5a6a3471782e9399129c98f3d529bbfd5..0000000000000000000000000000000000000000 Binary files a/en/application-dev/ability/figures/contextIntroduction.png and /dev/null differ diff --git a/en/application-dev/ability/figures/favsstage.png b/en/application-dev/ability/figures/favsstage.png deleted file mode 100644 index 45f6b0ef255b01730dc42023430391e1141291c2..0000000000000000000000000000000000000000 Binary files a/en/application-dev/ability/figures/favsstage.png and /dev/null differ diff --git a/en/application-dev/ability/figures/lifecycle.png b/en/application-dev/ability/figures/lifecycle.png deleted file mode 100644 index 694238d99c7e70d16d6bd1a37c86bcd599a9b2f3..0000000000000000000000000000000000000000 Binary files a/en/application-dev/ability/figures/lifecycle.png and /dev/null differ diff --git a/en/application-dev/ability/figures/stageabilitylifecyclecallback.png b/en/application-dev/ability/figures/stageabilitylifecyclecallback.png deleted file mode 100644 index 9e17ed71f1dc9d118a490109c1e5181d738e63db..0000000000000000000000000000000000000000 Binary files a/en/application-dev/ability/figures/stageabilitylifecyclecallback.png and /dev/null differ diff --git a/en/application-dev/ability/stage-ability-continuation.md b/en/application-dev/ability/stage-ability-continuation.md deleted file mode 100644 index 701b730a833a7b97f00398746cddae4d2856a248..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/stage-ability-continuation.md +++ /dev/null @@ -1,311 +0,0 @@ -# Ability Continuation Development - -## When to Use - -Ability continuation is to continue the current mission of an application, including the UI component state variables and distributed objects, on another device. The UI component state variables are used to synchronize UI data, and the distributed objects are used to synchronize memory data. - -## Available APIs - -The following table lists the APIs used for ability continuation. For details about the APIs, see [Ability](../reference/apis/js-apis-application-ability.md). - -**Table 1** Ability continuation APIs - -|API| Description| -|:------ | :------| -| onContinue(wantParam : {[key: string]: any}): OnContinueResult | Called by the initiator to store the data required for continuation. The return value indicates whether the continuation request is accepted. The value **AGREE** means that the continuation request is accepted, **REJECT** means that the continuation request is rejected, and **MISMATCH** means a version mismatch.| -| onCreate(want: Want, param: AbilityConstant.LaunchParam): void; | Called by the target to restore the data and UI page in the multi-instance ability scenario.| -| onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void; | Called by the target to restore the data and UI page in the singleton ability scenario.| - - - -**Figure 1** Ability continuation development - -![continuation_dev](figures/continuation-info.png) - -In effect, ability continuation is a cross-device ability startup that carries data. When a continuation action is initiated, the system on device A calls back **onContinue()** of the application. You must implement storage of the current data in this API. Then, the system initiates a cross-device ability startup on device B and transmits the data to device B. The system on device B calls back **onCreate()** or **onNewWant()**. You must implement restoration of the transmitted data in this API. - -## How to Develop - -The code snippets provided below are all from [Sample](https://gitee.com/openharmony/ability_dmsfwk/tree/master/services/dtbschedmgr/test/samples/continuationManualTestSuite). - -### Application Continuation - -1. Modify the configuration file. - - - Configure the application to support ability continuation. - - Set the **continuable** field in the **module.json5** file to **true**. The default value is **false**. If this parameter is set to **false**, the application cannot be continued on another device. - - ```javascript - { - "module": { - "abilities": [ - { - "continuable": true - } - ] - } - } - ``` - - - - - - Configure the application startup type. - - If **launchType** is set to **standard** in the **module.json5** file, the application is of the multi-instance launch type. During ability continuation, regardless of whether the application is already open, the target starts the application and restores the UI page. If **launchType** is set to **singleton**, the application is of the singleton launch type. If the application is already open, the target clears the existing page stack and restores the UI page. For more information, see "Launch Type" in [Ability Development](./stage-ability.md). - - Configure a multi-instance application as follows: - - ```javascript - { - "module": { - "abilities": [ - { - "launchType": "standard" - } - ] - } - } - ``` - - Configure a singleton application as follows or retain the default settings of **launchType**: - - ```javascript - { - "module": { - "abilities": [ - { - "launchType": "singleton" - } - ] - } - } - ``` - - - - - Apply for the distributed permissions. - - Declare the **DISTRIBUTED_DATASYNC** permission in the **module.json5** file for the application. - - ```javascript - "requestPermissions": [ - { - "name": "ohos.permission.DISTRIBUTED_DATASYNC" - }, - ``` - - - - This permission must be granted by the user in a dialog box when the application is started for the first time. To enable the application to display a dialog box to ask for the permission, add the following code to **onWindowStageCreate** of the **Ability** class: - - ```javascript - requestPermissions = async () => { - let permissions: Array = [ - "ohos.permission.DISTRIBUTED_DATASYNC" - ]; - let needGrantPermission = false - let accessManger = accessControl.createAtManager() - Logger.info("app permission get bundle info") - let bundleInfo = await bundle.getApplicationInfo(BUNDLE_NAME, 0, 100) - Logger.info(`app permission query permission ${bundleInfo.accessTokenId.toString()}`) - for (const permission of permissions) { - Logger.info(`app permission query grant status ${permission}`) - try { - let grantStatus = await accessManger.verifyAccessToken(bundleInfo.accessTokenId, permission) - if (grantStatus === PERMISSION_REJECT) { - needGrantPermission = true - break; - } - } catch (err) { - Logger.error(`app permission query grant status error ${permission} ${JSON.stringify(err)}`) - needGrantPermission = true - break; - } - } - if (needGrantPermission) { - Logger.info("app permission needGrantPermission") - try { - await this.context.requestPermissionsFromUser(permissions) - } catch (err) { - Logger.error(`app permission ${JSON.stringify(err)}`) - } - } else { - Logger.info("app permission already granted") - } - } - ``` - - - - -2. Implement the **onContinue()** API. - - The **onContinue()** API is called by the initiator to save the UI component state variables and memory data and prepare for continuation. After the application completes the continuation preparation, the system must return either **OnContinueResult.AGREE(0)** to accept the continuation request or an error code to reject the request. If this API is not implemented, the system rejects the continuation request by default. - - Modules to import: - - ```javascript - import Ability from '@ohos.application.Ability'; - import AbilityConstant from '@ohos.application.AbilityConstant'; - ``` - - To implement ability continuation, you must implement this API and have the value **AGREE** returned. - - You can obtain the target device ID (identified by the key **targetDevice**) and the version number (identified by the key **version**) of the application installed on the target device from the **wantParam** parameter of this API. The version number can be used for compatibility check. If the current application version is incompatible with that on the target device, **OnContinueResult.MISMATCH** can be returned to reject the continuation request. - - Example - - ```javascript - onContinue(wantParam : {[key: string]: any}) { - Logger.info(`onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`) - let workInput = AppStorage.Get('ContinueWork'); - // Set the user input data into wantParam. - wantParam["work"] = workInput // set user input data into want params - Logger.info(`onContinue input = ${wantParam["input"]}`); - return AbilityConstant.OnContinueResult.AGREE - } - ``` - - - -3. Implement the continuation logic in the **onCreate()** or **onNewWant()** API. - - The **onCreate()** API is called by the target. When the ability is started on the target device, this API is called to instruct the application to synchronize the memory data and UI component state, and triggers page restoration after the synchronization is complete. If the continuation logic is not implemented, the ability will be started in common startup mode and the page cannot be restored. - - The target device determines whether the startup is **LaunchReason.CONTINUATION** based on **launchReason** in **onCreate()**. - - After data restore is complete, call **restoreWindowStage** to trigger page restoration. - - - - You can also use **want.parameters.version** in the **want** parameter to obtain the application version number of the initiator. - - Example - - ```javascript - import Ability from '@ohos.application.Ability'; - import distributedObject from '@ohos.data.distributedDataObject'; - - export default class MainAbility extends Ability { - storage : LocalStorag; - - onCreate(want, launchParam) { - Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`) - if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) { - // Obtain the user data from the want parameter. - let workInput = want.parameters.work - Logger.info(`work input ${workInput}`) - AppStorage.SetOrCreate('ContinueWork', workInput) - - this.storage = new LocalStorage(); - this.context.restoreWindowStage(this.storage); - } - } - } - ``` -For a singleton ability, use **onNewWant()** to achieve the same implementation. - - - -### Data Continuation - -Use distributed objects. - -Distributed objects allow cross-device data synchronization like local variables. For two devices that form a Super Device, when data in the distributed data object of an application is added, deleted, or modified on a device, the data for the same application is also updated on the other device. Both devices can listen for the data changes and online and offline states of the other. For details, see [Distributed Data Object Development](../database/database-distributedobject-guidelines.md). - -In the ability continuation scenario, the distributed data object is used to synchronize the memory data from the local device to the target device. - -- In **onContinue()**, the initiator saves the data to be migrated to the distributed object, calls the **save()** API to save the data and synchronize the data to the target device, sets the session ID, and sends the session ID to the target device through **wantParam**. - - ```javascript - import Ability from '@ohos.application.Ability'; - import distributedObject from '@ohos.data.distributedDataObject'; - - var g_object = distributedObject.createDistributedObject({data:undefined}); - - export default class MainAbility extends Ability { - sessionId : string; - - onContinue(wantParam : {[key: string]: any}) { - Logger.info(`onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`) - - if (g_object.__sessionId === undefined) { - this.sessionId = distributedObject.genSessionId() - Logger.info(`onContinue generate new sessionId`) - } - else { - this.sessionId = g_object.__sessionId; - } - - wantParam["session"] = this.sessionId - g_object.data = AppStorage.Get('ContinueStudy'); - Logger.info(`onContinue sessionId = ${this.sessionId}, name = ${g_object.data}`) - g_object.setSessionId(this.sessionId); - g_object.save(wantParam.targetDevice, (result, data)=>{ - Logger.info("save callback"); - Logger.info("save sessionId " + data.sessionId); - Logger.info("save version " + data.version); - Logger.info("save deviceId " + data.deviceId); - }); - ``` - - - -- The target device obtains the session ID from **onCreate()**, creates a distributed object, and associates the distributed object with the session ID. In this way, the distributed object can be synchronized. Before calling **restoreWindowStage**, ensure that all distributed objects required for continuation have been associated. - - ```javascript - import Ability from '@ohos.application.Ability'; - import distributedObject from '@ohos.data.distributedDataObject'; - - var g_object = distributedObject.createDistributedObject({data:undefined}); - - export default class MainAbility extends Ability { - storage : LocalStorag; - - - onCreate(want, launchParam) { - Logger.info(`MainAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`) - if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) { - // Obtain the session ID of the distributed data object from the want parameter. - this.sessionId = want.parameters.session - Logger.info(`onCreate for continuation sessionId: ${this.sessionId}`) - - // Before fetching data from the remote device, reset g_object.data to undefined. - g_object.data = undefined; - // Set the session ID, so the target will fetch data from the remote device. - g_object.setSessionId(this.sessionId); - - AppStorage.SetOrCreate('ContinueStudy', g_object.data) - this.storage = new LocalStorage(); - this.context.restoreWindowStage(this.storage); - } - - } - } - ``` - - - -### More Information - -1. Timeout - - - If the application to be continued is not installed on the target device, the system checks whether the application can be installed on it and waits for a response for 4 seconds. If no response is received within 4 seconds, the caller receives a timeout error code, which means that the application cannot be installed on the target device. If the application can be installed, the system prompts the consumer to install the application on the target device. The consumer can initiate the continuation again after the installation. - - If the application to be continued has been installed on the target device, the system waits for a response to the continuation request for 20 seconds. If no response is received within 20 seconds, the caller receives a timeout error code, which means that the continuation fails. - -2. By default, the system supports page stack information migration, which means that the page stack of the initiator will be automatically migrated to the target device. No adaptation is required. - - - -### Restrictions - -1. The continuation must be performed between the same ability, which means the same bundle name, module name, and ability name. For details, see [Application Package Structure Configuration File](../quick-start/stage-structure.md). -2. Currently, the application can only implement the continuation capability. The continuation action must be initiated by the system. - - - -### Best Practice - - For better user experience, you are advised to use the **wantParam** parameter to transmit data smaller than 100 KB and use distributed objects to transmit data larger than 100 KB. diff --git a/en/application-dev/ability/stage-ability.md b/en/application-dev/ability/stage-ability.md deleted file mode 100644 index fcd7a5dcfdde6547237f34f83dbb9bf2488d2255..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/stage-ability.md +++ /dev/null @@ -1,323 +0,0 @@ -# Ability Development -## When to Use -Ability development in the [stage model](stage-brief.md) is significantly different from that in the FA model. The stage model requires you to declare the application package structure in the `module.json5` and `app.json5` files during application development. For details about the configuration file, see [Application Package Structure Configuration File](../quick-start/stage-structure.md). To develop an ability based on the stage model, implement the following logic: -- Create an ability that supports screen viewing and human-machine interaction. You must implement the following scenarios: ability lifecycle callbacks, obtaining ability configuration, requesting permissions, and notifying environment changes. -- Start an ability. You need to implement ability startup on the same device, on a remote device, or with a specified UI page. -- Call abilities. For details, see [Call Development](stage-call.md). -- Connect to and disconnect from a Service Extension ability. For details, see [Service Extension Ability Development](stage-serviceextension.md). -- Continue the ability on another device. For details, see [Ability Continuation Development](stage-ability-continuation.md). - -### Launch Type -An ability can be launched in the **standard**, **singleton**, or **specified** mode, as configured by `launchType` in the `module.json5` file. Depending on the launch type, the action performed when the ability is started differs, as described below. - -| Launch Type | Description |Action | -| ----------- | ------- |---------------- | -| standard | Multi-instance | A new instance is started each time an ability starts.| -| singleton | Singleton | The ability has only one instance in the system. If an instance already exists when an ability is started, that instance is reused.| -| specified | Instance-specific| The internal service of an ability determines whether to create multiple instances during running.| - -By default, the singleton mode is used. The following is an example of the `module.json5` file: -```json -{ - "module": { - "abilities": [ - { - "launchType": "singleton", - } - ] - } -} -``` -## Creating an Ability -### Available APIs -The table below describes the APIs provided by the `AbilityStage` class, which has the `context` attribute. For details about the APIs, see [AbilityStage](../reference/apis/js-apis-application-abilitystage.md). - -**Table 1** AbilityStage APIs -|API|Description| -|:------|:------| -|onCreate(): void|Called when an ability stage is created.| -|onAcceptWant(want: Want): string|Called when a specified ability is started.| -|onConfigurationUpdated(config: Configuration): void|Called when the global configuration is updated.| - -The table below describes the APIs provided by the `Ability` class. For details about the APIs, see [Ability](../reference/apis/js-apis-application-ability.md). - -**Table 2** Ability APIs - -|API|Description| -|:------|:------| -|onCreate(want: Want, param: AbilityConstant.LaunchParam): void|Called when an ability is created.| -|onDestroy(): void|Called when the ability is destroyed.| -|onWindowStageCreate(windowStage: window.WindowStage): void|Called when a `WindowStage` is created for the ability. You can use the `window.WindowStage` APIs to implement operations such as page loading.| -|onWindowStageDestroy(): void|Called when the `WindowStage` is destroyed for the ability.| -|onForeground(): void|Called when the ability is switched to the foreground.| -|onBackground(): void|Called when the ability is switched to the background.| -|onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void|Called when the ability launch type is set to `singleton`.| -|onConfigurationUpdated(config: Configuration): void|Called when the configuration of the environment where the ability is running is updated.| -### Implementing AbilityStage and Ability Lifecycle Callbacks -To create Page abilities for an application in the stage model, you must implement the `AbilityStage` class and ability lifecycle callbacks, and use the `Window` APIs to set the pages. The sample code is as follows: -1. Import the `AbilityStage` module. - ``` - import AbilityStage from "@ohos.application.AbilityStage" - ``` -2. Implement the `AbilityStage` class. The default relative path generated by the APIs is **entry\src\main\ets\Application\AbilityStage.ts**. - ```ts - export default class MyAbilityStage extends AbilityStage { - onCreate() { - console.log("MyAbilityStage onCreate") - } - } - ``` -3. Import the `Ability` module. - ```js - import Ability from '@ohos.application.Ability' - ``` -4. Implement the lifecycle callbacks of the `Ability` class. The default relative path generated by the APIs is **entry\src\main\ets\MainAbility\MainAbility.ts**. - - In the `onWindowStageCreate(windowStage)` API, use `loadContent` to set the application page to be loaded. For details about how to use the `Window` APIs, see [Window Development](../windowmanager/application-window-stage.md). - ```ts - export default class MainAbility extends Ability { - onCreate(want, launchParam) { - console.log("MainAbility onCreate") - } - - onDestroy() { - console.log("MainAbility onDestroy") - } - - onWindowStageCreate(windowStage) { - console.log("MainAbility onWindowStageCreate") - - windowStage.loadContent("pages/index").then(() => { - console.log("MainAbility load content succeed") - }).catch((error) => { - console.error("MainAbility load content failed with error: " + JSON.stringify(error)) - }) - } - - onWindowStageDestroy() { - console.log("MainAbility onWindowStageDestroy") - } - - onForeground() { - console.log("MainAbility onForeground") - } - - onBackground() { - console.log("MainAbility onBackground") - } - } - ``` -### Obtaining AbilityStage and Ability Configurations -Both the `AbilityStage` and `Ability` classes have the `context` attribute. An application can obtain the context of an `Ability` instance through `this.context` to obtain the configuration details. - -The following example shows how an application obtains the bundle code directory, HAP file name, ability name, and system language through the `context` attribute in the `AbilityStage` class. The sample code is as follows: - -```ts -import AbilityStage from "@ohos.application.AbilityStage" -export default class MyAbilityStage extends AbilityStage { - onCreate() { - console.log("MyAbilityStage onCreate") - let context = this.context - console.log("MyAbilityStage bundleCodeDir" + context.bundleCodeDir) - - let currentHapModuleInfo = context.currentHapModuleInfo - console.log("MyAbilityStage hap module name" + currentHapModuleInfo.name) - console.log("MyAbilityStage hap module mainAbilityName" + currentHapModuleInfo.mainAbilityName) - - let config = this.context.config - console.log("MyAbilityStage config language" + config.language) - } -} -``` - -The following example shows how an application obtains the bundle code directory, HAP file name, ability name, and system language through the `context` attribute in the `Ability` class. The sample code is as follows: -```ts -import Ability from '@ohos.application.Ability' -export default class MainAbility extends Ability { - onCreate(want, launchParam) { - console.log("MainAbility onCreate") - let context = this.context - console.log("MainAbility bundleCodeDir" + context.bundleCodeDir) - - let abilityInfo = this.context.abilityInfo; - console.log("MainAbility ability bundleName" + abilityInfo.bundleName) - console.log("MainAbility ability name" + abilityInfo.name) - - let config = this.context.config - console.log("MainAbility config language" + config.language) - } -} -``` -### Requesting Permissions -If an application needs to obtain user privacy information or use system capabilities, for example, obtaining location information or using the camera to take photos or record videos, it must request the respective permission from consumers. During application development, you need to specify the involved sensitive permissions, declare the required permissions in `module.json5`, and use the `requestPermissionsFromUser` API to request the permission from consumers in the form of a dialog box. The following uses the permission for calendar access as an example. - -Declare the required permission in the `module.json5` file. -```json -"requestPermissions": [ - { - "name": "ohos.permission.READ_CALENDAR" - } -] -``` -Request the permission from consumers in the form of a dialog box: -```ts -let context = this.context -let permissions: Array = ['ohos.permission.READ_CALENDAR'] -context.requestPermissionsFromUser(permissions).then((data) => { - console.log("Succeed to request permission from user with data: " + JSON.stringify(data)) -}).catch((error) => { - console.log("Failed to request permission from user with error: " + JSON.stringify(error)) -}) -``` -### Notifying of Environment Changes -Environment changes include changes of global configurations and ability configurations. Currently, the global configurations include the system language and color mode. The change of global configurations is generally triggered by configuration items in **Settings** or icons in **Control Panel**. The ability configuration is specific to a single `Ability` instance, including the display ID, screen resolution, and screen orientation. The configuration is related to the display where the ability is located, and the change is generally triggered by the window. For details on the configuration, see [Configuration](../reference/apis/js-apis-configuration.md). - -For an application in the stage model, when the configuration changes, its abilities are not restarted, but the `onConfigurationUpdated(config: Configuration)` callback is triggered. If the application needs to perform processing based on the change, you can overwrite `onConfigurationUpdated`. Note that the `Configuration` object in the callback contains all the configurations of the current ability, not only the changed configurations. - -The following example shows the implementation of the `onConfigurationUpdated` callback in the `AbilityStage` class. The callback is triggered when the system language and color mode are changed. -```ts -import Ability from '@ohos.application.Ability' -import ConfigurationConstant from '@ohos.application.ConfigurationConstant' - -export default class MyAbilityStage extends AbilityStage { - onConfigurationUpdated(config) { - if (config.colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) { - console.log('colorMode changed to dark') - } - } -} -``` - -The following example shows the implementation of the `onConfigurationUpdated` callback in the `Ability` class. The callback is triggered when the system language, color mode, or display parameters (such as the direction and density) change. -```ts -import Ability from '@ohos.application.Ability' -import ConfigurationConstant from '@ohos.application.ConfigurationConstant' - -export default class MainAbility extends Ability { - direction : number; - - onCreate(want, launchParam) { - this.direction = this.context.config.direction - } - - onConfigurationUpdated(config) { - if (this.direction !== config.direction) { - console.log(`direction changed to ${config.direction}`) - } - } -} -``` -## Starting an Ability -### Available APIs -The `Ability` class has the `context` attribute, which belongs to the `AbilityContext` class. The `AbilityContext` class has the `abilityInfo`, `currentHapModuleInfo`, and other attributes as well as the APIs used for starting abilities. For details, see [AbilityContext](../reference/apis/js-apis-ability-context.md). - -**Table 3** AbilityContext APIs -|API|Description| -|:------|:------| -|startAbility(want: Want, callback: AsyncCallback\): void|Starts an ability.| -|startAbility(want: Want, options?: StartOptions): Promise\|Starts an ability.| -|startAbilityWithAccount(want: Want, accountId: number, callback: AsyncCallback\): void|Starts an ability with the account ID.| -|startAbilityWithAccount(want: Want, accountId: number, options?: StartOptions): Promise\|Starts an ability with the account ID.| -|startAbilityForResult(want: Want, callback: AsyncCallback\): void|Starts an ability with the returned result.| -|startAbilityForResult(want: Want, options?: StartOptions): Promise\|Starts an ability with the returned result.| -|startAbilityForResultWithAccount(want: Want, accountId: number, callback: AsyncCallback\): void|Starts an ability with the execution result and account ID.| -|startAbilityForResultWithAccount(want: Want, accountId: number, options?: StartOptions): Promise\|Starts an ability with the execution result and account ID.| -### Starting an Ability on the Same Device -An application can obtain the context of an `Ability` instance through `this.context` and then use the `startAbility` API in the `AbilityContext` class to start the ability. The ability can be started by specifying `Want`, `StartOptions`, and `accountId`, and the operation result can be returned using a callback or `Promise` instance. The sample code is as follows: -```ts -let context = this.context -var want = { - "deviceId": "", - "bundleName": "com.example.MyApplication", - "abilityName": "MainAbility" -}; -context.startAbility(want).then(() => { - console.log("Succeed to start ability") -}).catch((error) => { - console.error("Failed to start ability with error: "+ JSON.stringify(error)) -}) -``` - -### Starting an Ability on a Remote Device ->This feature applies only to system applications, since the `getTrustedDeviceListSync` API of the `DeviceManager` class is open only to system applications. -In the cross-device scenario, you must specify the ID of the remote device. The sample code is as follows: -```ts -let context = this.context -var want = { - "deviceId": getRemoteDeviceId(), - "bundleName": "com.example.MyApplication", - "abilityName": "MainAbility" -}; -context.startAbility(want).then(() => { - console.log("Succeed to start remote ability") -}).catch((error) => { - console.error("Failed to start remote ability with error: " + JSON.stringify(error)) -}) -``` -Obtain the ID of a specified device from `DeviceManager`. The sample code is as follows: -```ts -import deviceManager from '@ohos.distributedHardware.deviceManager'; -function getRemoteDeviceId() { - if (typeof dmClass === 'object' && dmClass != null) { - var list = dmClass.getTrustedDeviceListSync(); - if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { - console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null"); - return; - } - console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId); - return list[0].deviceId; - } else { - console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null"); - } -} -``` -Request the permission `ohos.permission.DISTRIBUTED_DATASYNC` from consumers. This permission is used for data synchronization. For details about the sample code for requesting the permission, see [Requesting Permissions](##requesting-permissions). -### Starting an Ability with the Specified Page -If the launch type of an ability is set to `singleton` and the ability has been started, the `onNewWant` callback is triggered when the ability is started again. You can pass start options through the `want`. For example, to start an ability with the specified page, use the `uri` or `parameters` parameter in the `want` to pass the page information. Currently, the ability in the stage model cannot directly use the `router` capability. You must pass the start options to the custom component and invoke the `router` method to display the specified page during the custom component lifecycle management. The sample code is as follows: - -When using `startAbility` to start an ability again, use the `uri` parameter in the `want` to pass the page information. -```ts -async function reStartAbility() { - try { - await this.context.startAbility({ - bundleName: "com.sample.MyApplication", - abilityName: "MainAbility", - uri: "pages/second" - }) - console.log('start ability succeed') - } catch (error) { - console.error(`start ability failed with ${error.code}`) - } -} -``` - -Obtain the `want` parameter that contains the page information from the `onNewWant` callback of the ability. -```ts -import Ability from '@ohos.application.Ability' - -export default class MainAbility extends Ability { - onNewWant(want, launchParams) { - globalThis.newWant = want - } -} -``` - -Obtain the `want` parameter that contains the page information from the custom component and process the route based on the URI. -```ts -import router from '@ohos.router' - -@Entry -@Component -struct Index { - newWant = undefined - - onPageShow() { - console.info('Index onPageShow') - let newWant = globalThis.newWant - if (newWant.hasOwnProperty("uri")) { - router.push({ uri: newWant.uri }); - globalThis.newWant = undefined - } - } -} -``` diff --git a/en/application-dev/ability/stage-brief.md b/en/application-dev/ability/stage-brief.md deleted file mode 100644 index 0b4bfe8e3ec2943528e3bd2e8b640dea4ffbd070..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/stage-brief.md +++ /dev/null @@ -1,97 +0,0 @@ -# Stage Model Overview - -## Design Ideas - -The stage model is designed to make it easier to develop complex applications in the distributed environment. - -The following figure shows the design ideas of the stage model. - -![stagedesign](figures/stagedesign.png) - -The stage model is designed based on the following considerations: - -- **Balance between application capabilities and overall system power consumption** - - On a running device, resources are preferentially guaranteed for foreground applications, on the prerequisites that the overall power consumption requirements of the system are met. The stage model balances the application capabilities and overall system power consumption through ability and UI separation, strict background control, scenario-based service mechanism, and single-process model. - -- **Native support for component continuation and collaboration** - - OpenHarmony natively supports distributed deployment. Therefore, its application framework must be designed for easier component migration and collaboration. The stage model achieves this design objective by providing features such as separation between ability and UI as well as integration of UI display and service capabilities. - -- **Support for multiple device types and window forms** - - To support multiple device types and facilitate the implementation of different window forms, the component manager and window manager must be decoupled at the architecture layer for easier tailoring. To achieve this goal, the stage model redefines the ability lifecycle and implements unidirectional dependency for the component manager and window manager. - - -## Basic Concepts - -The following figure shows the basic concepts in the stage model. - -![stageconcept](figures/stageconcept.png) - -- **HAP**: Harmony Ability Package, also called module, which is the basic unit for building, distributing, and loading OpenHarmony applications. Each HAP has a unique name, which is called **moduleName**, in an application. -- **Bundle**: an OpenHarmony application identified by **appid**. A bundle can contain multiple HAP files. Each application has a **bundleName**. However, **bundleName** must be used together with **appid** and other information to uniquely identify an application. -- **AbilityStage**: runtime class of an HAP. It is created when the HAP is loaded to the process for the first time and is visible to developers in the runtime. -- **Application**: runtime class of a bundle, which is invisible to developers in the runtime. -- **Context**: base class that the context classes of **Ability** and **ExtensionAbility** classes inherit. This class provides various capabilities that can be invoked by developers in the runtime, and various information such as the bundle name, module name, and path. -- **Ability**: class that provides lifecycle callbacks, holds the **AbilityContext** class, and supports component continuation and collaboration. -- **ExtensionAbility**: general name of scenario-based service extension abilities. The system defines multiple scenario-based **ExtensionAbility** classes, each of which has its own **ExtensionContext**. -- **WindowStage**: local window manager. -- **Window**: basic unit managed by the window manager. It has an ArkUI engine instance. -- **ArkUI Page**: ArkUI development framework page. - - -## Lifecycle - -The ability and ability stage lifecycles are the rudiments of the basic process of an application. For details about how these lifecycles differ from those in the FA model, see [Ability Framework Overview](ability-brief.md). This section focuses on the ability lifecycle transition and the scheduling relationships between the ability, ability stage, and window stage. - -![stageabilitylifecyclecallback](figures/stageabilitylifecyclecallback.png) - -To implement device-specific tailoring and multi-window scalability, OpenHarmony decouples the component manager from the window manager. The ability lifecycle defined in the stage model includes only the creation, destruction, foreground, and background states. The gain focus and lose focus states that are closely related to UI content are defined in the window stage. This implements weak coupling between the abilities and windows. On the service side, the window manager notifies the component manager of the foreground and background changes, so the component manager only senses the foreground and background changes but not the focus changes. - - -## Ability Instances and Missions - -Abilities can be started in any of the following modes: - -+ **Singleton**: For each type of ability, only one instance exists in the application process. **Ability1** in the figure below is started in singleton mode. - -+ **Standard**: Each time **startAbility** is called, an instance of the specified ability type is created in the application process. **Ability2** in the figure below is started in standard mode. - -+ **Specified**: Before creating an **AbilityRecord**, you can create a key for the instance. Each time **startAbility** is called, the system asks the application which ability instance (corresponding to a key) will be used. **Ability3** in the figure below is started in specified mode. - -Each ability instance corresponds to a mission in **Launcher Recent**. - -The mission corresponding to an ability instance has a snapshot of the ability instance. After the ability instance is destroyed, the ability class information and snapshot are retained in the mission until the user deletes the information or the storage space reaches the upper limit. - - ![AbilityComponentInstanceMission](figures/AbilityComponentInstanceMission.png) - -## ExtensionAbility Mechanism - -Different from the ability used for page display, the extension ability provides a restricted service running environment. It has the following features: - -- Its process runs independently from the main process and shares the same storage sandbox with the main process. There is no inter-process communication (IPC) between the process and the main process. - -- It has an independent context that provides scenario-specific APIs. - -- It is created by the system, rather than by applications. - -- The lifecycles of the extension ability and process are managed by the system. - -The following figure uses the widget scenario as an example. You can inherit from the **FormExtensionAbility** base class to provide the widget details. The lifecycle of the **FormExtensionAbility** instance and that of the extension ability process where the instance is located are managed by **FormManagerService**, which is a system service. - -![ExtensionAbility](figures/ExtensionAbility.png) - -## Process Model - -All OpenHarmony applications are designed to meet the single-process model. In the single-process model, all processes in the application are created and managed by the system. Each application supports a maximum of three types of processes: - -- Main process: runs all ability components, pages, and service logic. - -- Extension process: runs classes derived from **ExtensionAbility** in the application. The lifecycle of this process is managed by a scenario-specific system service. - -- Render process: created for the WebView and used to load the WebView rendering library. - - The following figure shows the process model of an application. - - ![stageprocessmodel](figures/stageprocessmodel.png) diff --git a/en/application-dev/ability/stage-call.md b/en/application-dev/ability/stage-call.md deleted file mode 100644 index 390e1b6c3ce5393956d0a7801f362ab7f49578a4..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/stage-call.md +++ /dev/null @@ -1,284 +0,0 @@ -# Ability Call Development -## When to Use -Ability call is an extension of the ability capability. It enables an ability to be invoked by and communicate with external systems. The ability invoked can be either started in the foreground or created and run in the background. You can use the ability call to implement data sharing between two abilities (caller ability and callee ability) through inter-process communication (IPC). - -The core API used for the ability call is `startAbilityByCall`, which differs from `startAbility` in the following ways: - - `startAbilityByCall` supports ability startup in the foreground and background, whereas `startAbility` supports ability startup in the foreground only. - - The caller ability can use the `Caller` object returned by `startAbilityByCall` to communicate with the callee ability, but `startAbility` does not provide the communication capability. - -Ability call is usually used in the following scenarios: -- Communicating with the callee ability -- Starting the callee ability in the background - -**Table 1** Terms used in the ability call -|Term|Description| -|:------|:------| -|Caller ability|Ability that triggers the ability call.| -|Callee ability|Ability invoked by the ability call.| -|Caller |Object returned by `startAbilityByCall` and used by the caller ability to communicate with the callee ability.| -|Callee |Object held by the callee ability to communicate with the caller ability.| -|IPC |Inter-process communication.| - -The ability call process is as follows: - - The caller ability uses `startAbilityByCall` to obtain a `Caller` object and uses `call()` of the `Caller` object to send data to the callee ability. - - The callee ability, which holds a `Callee` object, uses `on()` of the `Callee` object to register a callback. This callback is invoked when the callee ability receives data from the caller ability. -![stage-call](figures/stage-call.png) - -> **NOTE**
-> The launch type of the callee ability must be `singleton`. -> Currently, only system applications can use the ability call. - -## Available APIs -The table below describes the ability call APIs. For details, see [Ability](../reference/apis/js-apis-application-ability.md#caller). - -**Table 2** Ability call APIs -|API|Description| -|:------|:------| -|startAbilityByCall(want: Want): Promise\|Starts an ability in the foreground (through the `want` configuration) or background (default) and obtains the `Caller` object for communication with the ability. For details, see [AbilityContext](../reference/apis/js-apis-ability-context.md#abilitycontextstartabilitybycall) or [ServiceExtensionContext](../reference/apis/js-apis-service-extension-context.md#serviceextensioncontextstartabilitybycall).| -|on(method: string, callback: CalleeCallBack): void|Callback invoked when the callee ability registers a method.| -|off(method: string): void|Callback invoked when the callee ability deregisters a method.| -|call(method: string, data: rpc.Sequenceable): Promise\|Sends agreed sequenceable data to the callee ability.| -|callWithResult(method: string, data: rpc.Sequenceable): Promise\|Sends agreed sequenceable data to the callee ability and obtains the agreed sequenceable data returned by the callee ability.| -|release(): void|Releases the `Caller` object.| -|onRelease(callback: OnReleaseCallBack): void|Callback invoked when the `Caller` object is released.| - -## How to Develop -The procedure for developing the ability call is as follows: -1. Create a callee ability. -2. Access the callee ability. -> **NOTE** -> -> The code snippets provided in the **How to Develop** section are used to show specific development steps. They may not be able to run independently. -### Creating a Callee Ability -For the callee ability, implement the callback to receive data and the methods to marshal and unmarshal data. When data needs to be received, use `on()` to register a listener. When data does not need to be received, use `off()` to deregister the listener. -**1. Configure the ability launch type.** - - Set `launchType` of the callee ability to `singleton` in the `module.json5` file. - -|JSON Field|Description| -|:------|:------| -|"launchType"|Ability launch type. Set this parameter to `singleton`.| - -An example of the ability configuration is as follows: -```json -"abilities":[{ - "name": ".CalleeAbility", - "srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts", - "launchType": "singleton", - "description": "$string:CalleeAbility_desc", - "icon": "$media:icon", - "label": "$string:CalleeAbility_label", - "visible": true -}] -``` -**2. Import the Ability module.** -```ts -import Ability from '@ohos.application.Ability' -``` -**3. Define the agreed sequenceable data.** - - The data formats sent and received by the caller and callee abilities must be consistent. In the following example, the data formats are number and string. The code snippet is as follows: -```ts -export default class MySequenceable { - num: number = 0 - str: string = "" - - constructor(num, string) { - this.num = num - this.str = string - } - - marshalling(messageParcel) { - messageParcel.writeInt(this.num) - messageParcel.writeString(this.str) - return true - } - - unmarshalling(messageParcel) { - this.num = messageParcel.readInt() - this.str = messageParcel.readString() - return true - } -} -``` -**4. Implement `Callee.on` and `Callee.off`.** - - The time to register a listener for the callee ability depends on your application. The data sent and received before the listener is registered and that after the listener is deregistered are not processed. In the following example, the `MSG_SEND_METHOD` listener is registered in `onCreate` of the ability and deregistered in `onDestroy`. After receiving sequenceable data, the application processes the data and returns the data result. You need to implement processing based on service requirements. The code snippet is as follows: -```ts -const TAG: string = '[CalleeAbility]' -const MSG_SEND_METHOD: string = 'CallSendMsg' - -function sendMsgCallback(data) { - console.log('CalleeSortFunc called') - - // Obtain the sequenceable data sent by the caller ability. - let receivedData = new MySequenceable(0, '') - data.readSequenceable(receivedData) - console.log(`receiveData[${receivedData.num}, ${receivedData.str}]`) - - // Process the data. - // Return the sequenceable data result to the caller ability. - return new MySequenceable(receivedData.num + 1, `send ${receivedData.str} succeed`) -} - -export default class CalleeAbility extends Ability { - onCreate(want, launchParam) { - try { - this.callee.on(MSG_SEND_METHOD, sendMsgCallback) - } catch (error) { - console.log(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`) - } - } - - onDestroy() { - try { - this.callee.off(MSG_SEND_METHOD) - } catch (error) { - console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`) - } - } -} -``` - -### Accessing the Callee Ability -**1. Import the Ability module.** -```ts -import Ability from '@ohos.application.Ability' -``` -**2. Obtain the `Caller` object.** - - The `context` attribute of the ability implements `startAbilityByCall` to obtain the `Caller` object for communication. The following example uses `this.context` to obtain the `context` attribute of the ability, uses `startAbilityByCall` to start the callee ability, obtain the `Caller` object, and register the `onRelease` listener of the caller ability. You need to implement processing based on service requirements. The code snippet is as follows: -```ts -// Register the onRelease listener of the caller ability. -private regOnRelease(caller) { - try { - caller.onRelease((msg) => { - console.log(`caller onRelease is called ${msg}`) - }) - console.log('caller register OnRelease succeed') - } catch (error) { - console.log(`caller register OnRelease failed with ${error}`) - } -} - -async onButtonGetCaller() { - try { - this.caller = await context.startAbilityByCall({ - bundleName: 'com.samples.CallApplication', - abilityName: 'CalleeAbility' - }) - if (this.caller === undefined) { - console.log('get caller failed') - return - } - console.log('get caller success') - this.regOnRelease(this.caller) - } catch (error) { - console.log(`get caller failed with ${error}`) - } -} -``` - In the cross-device scenario, you need to specify the ID of the peer device. The code snippet is as follows: -```ts -async onButtonGetRemoteCaller() { - var caller = undefined - var context = this.context - - context.startAbilityByCall({ - deviceId: getRemoteDeviceId(), - bundleName: 'com.samples.CallApplication', - abilityName: 'CalleeAbility' - }).then((data) => { - if (data != null) { - caller = data - console.log('get remote caller success') - // Register the onRelease listener of the caller ability. - caller.onRelease((msg) => { - console.log(`remote caller onRelease is called ${msg}`) - }) - console.log('remote caller register OnRelease succeed') - } - }).catch((error) => { - console.error(`get remote caller failed with ${error}`) - }) -} -``` - Obtain the ID of the peer device from `DeviceManager`. Note that the `getTrustedDeviceListSync` API is open only to system applications. The code snippet is as follows: -```ts -import deviceManager from '@ohos.distributedHardware.deviceManager'; -var dmClass; -function getRemoteDeviceId() { - if (typeof dmClass === 'object' && dmClass != null) { - var list = dmClass.getTrustedDeviceListSync() - if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { - console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null") - return - } - console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId) - return list[0].deviceId - } else { - console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null") - } -} -``` - In the cross-device scenario, your application must also apply for the data synchronization permission from end users. The code snippet is as follows: -```ts -requestPermission() { - let context = this.context - let permissions: Array = ['ohos.permission.DISTRIBUTED_DATASYNC'] - context.requestPermissionsFromUser(permissions).then((data) => { - console.log("Succeed to request permission from user with data: "+ JSON.stringify(data)) - }).catch((error) => { - console.log("Failed to request permission from user with error: "+ JSON.stringify(error)) - }) -} -``` -**3. Send agreed sequenceable data.** - - The sequenceable data can be sent to the callee ability with or without a return value. The method and sequenceable data must be consistent with those of the callee ability. The following example describes how to send data to the callee ability. The code snippet is as follows: -```ts -const MSG_SEND_METHOD: string = 'CallSendMsg' -async onButtonCall() { - try { - let msg = new MySequenceable(1, 'origin_Msg') - await this.caller.call(MSG_SEND_METHOD, msg) - } catch (error) { - console.log(`caller call failed with ${error}`) - } -} -``` - - In the following, `CallWithResult` is used to send data `originMsg` to the callee ability and assign the data processed by the `CallSendMsg` method to `backMsg`. The code snippet is as follows: -```ts -const MSG_SEND_METHOD: string = 'CallSendMsg' -originMsg: string = '' -backMsg: string = '' -async onButtonCallWithResult(originMsg, backMsg) { - try { - let msg = new MySequenceable(1, originMsg) - const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg) - console.log('caller callWithResult succeed') - - let result = new MySequenceable(0, '') - data.readSequenceable(result) - backMsg(result.str) - console.log(`caller result is [${result.num}, ${result.str}]`) - } catch (error) { - console.log(`caller callWithResult failed with ${error}`) - } -} -``` -**4. Release the `Caller` object.** - - When the `Caller` object is no longer required, use `release()` to release it. The code snippet is as follows: -```ts -releaseCall() { - try { - this.caller.release() - this.caller = undefined - console.log('caller release succeed') - } catch (error) { - console.log(`caller release failed with ${error}`) - } -} -``` diff --git a/en/application-dev/ability/stage-formextension.md b/en/application-dev/ability/stage-formextension.md deleted file mode 100644 index fa90f267c13c0fa002233f585ca7c6b3c9904637..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/stage-formextension.md +++ /dev/null @@ -1,415 +0,0 @@ -# Stage Widget Development - -## Widget Overview - -A widget is a set of UI components used to display important information or operations for an application. It provides users with direct access to a desired application service, without requiring them to open the application. - -A widget displays brief information about an application on the UI of another application (host application, currently system applications only) and provides basic interactive functions such as opening a UI page or sending a message. - -Basic concepts: - -- Widget provider: an atomic service that controls what and how content is displayed in a widget and interacts with users. -- Widget host: an application that displays the widget content and controls the position where the widget is displayed in the host application. -- Widget Manager: a resident agent that manages widgets added to the system and provides functions such as periodic widget update. - -> **NOTE** -> -> The widget host and provider do not keep running all the time. The Widget Manager starts the widget provider to obtain widget information when a widget is added, deleted, or updated. - -You only need to develop widget content as the widget provider. The system automatically handles the work done by the widget host and Widget Manager. - -The widget provider controls the widget content to display, component layout, and click events bound to components. - -## When to Use - -Stage widget development refers to the development conducted by the widget provider based on the [stage model](stage-brief.md). As a widget provider, you need to carry out the following operations: - -- Develop the lifecycle callbacks in **FormExtension**. -- Create a **FormBindingData** instance. -- Update a widget through **FormProvider**. -- Develop the widget UI page. - -## Available APIs - -The **FormExtension** class has the following APIs. For details, see [FormExtension](../reference/apis/js-apis-formextension.md). - -**Table 1** FormExtension APIs - -| API | Description | -| :----------------------------------------------------------- | :------------------------------------------- | -| onCreate(want: Want): formBindingData.FormBindingData | Called to notify the widget provider that a **Form** instance (widget) has been created. | -| onCastToNormal(formId: string): void | Called to notify the widget provider that a temporary widget has been converted to a normal one.| -| onUpdate(formId: string): void | Called to notify the widget provider that a widget has been updated. | -| onVisibilityChange(newStatus: { [key: string]: number }): void | Called to notify the widget provider of the change in widget visibility. | -| onEvent(formId: string, message: string): void | Called to instruct the widget provider to receive and process a widget event. | -| onDestroy(formId: string): void | Called to notify the widget provider that a **Form** instance (widget) has been destroyed. | -| onConfigurationUpdated(config: Configuration): void; | Called when the configuration of the environment where the widget is running is updated. | - -The **FormExtension** class also has a member context, that is, the **FormExtensionContext** class. For details, see [FormExtensionContext](../reference/apis/js-apis-formextensioncontext.md). - -**Table 2** FormExtensionContext APIs - -| API | Description | -| :----------------------------------------------------------- | :----------------------------------------------------------- | -| startAbility(want: Want, callback: AsyncCallback<void>): void | Starts an ability. This API uses an asynchronous callback to return the result. (This is a system API and cannot be called by third-party applications.)| -| startAbility(want: Want): Promise<void> | Starts an ability. This API uses a promise to return the result. (This is a system API and cannot be called by third-party applications.)| - -For details about the **FormProvider** APIs, see [FormProvider](../reference/apis/js-apis-formprovider.md). - -**Table 3** FormProvider APIs - -| API | Description | -| :----------------------------------------------------------- | :------------------------------------------------ | -| setFormNextRefreshTime(formId: string, minute: number, callback: AsyncCallback<void>): void; | Sets the next refresh time for a widget. This API uses an asynchronous callback to return the result. | -| setFormNextRefreshTime(formId: string, minute: number): Promise<void>; | Sets the next refresh time for a widget. This API uses a promise to return the result.| -| updateForm(formId: string, formBindingData: FormBindingData, callback: AsyncCallback<void>): void; | Updates a widget. This API uses an asynchronous callback to return the result. | -| updateForm(formId: string, formBindingData: FormBindingData): Promise<void>; | Updates a widget. This API uses a promise to return the result. | - -## How to Develop - -### Creating a FormExtension Instance - -To create a widget in the stage model, implement the lifecycle callbacks of **FormExtension**. The sample code is as follows: - -1. Import the required modules. - - ```javascript - import FormExtension from '@ohos.application.FormExtension' - import formBindingData from '@ohos.application.formBindingData' - import formInfo from '@ohos.application.formInfo' - import formProvider from '@ohos.application.formProvider' - ``` - -2. Implement the lifecycle callbacks of **FormExtension**. - - ```javascript - export default class FormAbility extends FormExtension { - onCreate(want) { - console.log('FormAbility onCreate'); - // Persistently store widget information for subsequent use, such as widget instance retrieval or update. - let obj = { - "title": "titleOnCreate", - "detail": "detailOnCreate" - }; - let formData = formBindingData.createFormBindingData(obj); - return formData; - } - onCastToNormal(formId) { - // Called when the widget host converts the temporary widget into a normal one. The widget provider should do something to respond to the conversion. - console.log('FormAbility onCastToNormal'); - } - onUpdate(formId) { - // To support scheduled update, periodic update, or update requested by the widget host, override this method for widget data update. - console.log('FormAbility onUpdate'); - let obj = { - "title": "titleOnUpdate", - "detail": "detailOnUpdate" - }; - let formData = formBindingData.createFormBindingData(obj); - formProvider.updateForm(formId, formData).catch((error) => { - console.log('FormAbility updateForm, error:' + JSON.stringify(error)); - }); - } - onVisibilityChange(newStatus) { - // Called when the widget host initiates an event about visibility changes. The widget provider should do something to respond to the notification. - console.log('FormAbility onVisibilityChange'); - } - onEvent(formId, message) { - // If the widget supports event triggering, override this method and implement the trigger. - console.log('FormAbility onEvent'); - } - onDestroy(formId) { - // Delete widget data. - console.log('FormAbility onDestroy'); - } - onConfigurationUpdated(config) { - console.log('FormAbility onConfigurationUpdated, config:' + JSON.stringify(config)); - } - } - ``` - -### Configuring the Widget Configuration File - -- Configure Extension ability information under **extensionAbilities** in the **module.json5** file. The internal field structure is described as follows: - - | Field | Description | Data Type | Default | - | ----------- | ------------------------------------------------------------ | ---------- | -------------------- | - | name | Name of the Extension ability. This field must be specified. | String | No | - | srcEntrance | Path of the Extension ability lifecycle code. This field must be specified.| String | No | - | description | Description of the Extension ability. The value can be a string or a resource index to descriptions in multiple languages.| String | Yes (initial value: left empty)| - | icon | Index of the Extension ability icon file. | String | Yes (initial value: left empty)| - | label | Descriptive information about the Extension ability presented externally. The value can be a string or a resource index to the description.| String | Yes (initial value: left empty)| - | type | Type of the Extension ability. In the current development scenario, set this field to **form**.| String | No | - | permissions | Permissions required for abilities of another application to call the current ability. | String array| Yes (initial value: left empty)| - | metadata | Metadata (configuration information) of the Extension ability.| Object | Yes (initial value: left empty) | - - For a Form Extension ability, you must specify **metadata**. Specifically, set **name** to **ohos.extension.form** (fixed), and set **resource** to the index of the widget configuration information. - - A configuration example is as follows: - - ```json - "extensionAbilities": [{ - "name": "FormAbility", - "srcEntrance": "./ets/FormAbility/FormAbility.ts", - "label": "$string:form_FormAbility_label", - "description": "$string:form_FormAbility_desc", - "type": "form", - "metadata": [{ - "name": "ohos.extension.form", - "resource": "$profile:form_config" - }] - }] - ``` - -- Configure the widget configuration information. **resource** in **metadata** specifies the index of the widget configuration information. For example, **$profile:form_config** means that **form_config.json** in the **resources/base/profile/** directory of the development view is used as the widget profile configuration file. - - The internal field structure is described as follows: - - | Field | Description | Data Type | Default | - | ------------------- | ------------------------------------------------------------ | ---------- | ------------------------ | - | name | Class name of a widget. The value is a string with a maximum of 127 bytes. | String | No | - | description | Description of the widget. The value can be a string or a resource index to descriptions in multiple languages. The value is a string with a maximum of 255 bytes.| String | Yes (initial value: left empty) | - | src | Full path of the UI code corresponding to the widget. | String | No | - | window | Window-related configurations. | Object | Yes | - | isDefault | Whether the widget is a default one. Each ability has only one default widget.
**true**: The widget is the default one.
**false**: The widget is not the default one.| Boolean | No | - | colorMode | Color mode of the widget. Available values are as follows:
**auto**: The widget adopts the auto-adaptive color mode.
**dark**: The widget adopts the dark color mode.
**light**: The widget adopts the light color mode.| String | Yes (initial value: **auto**)| - | supportDimensions | Grid styles supported by the widget. Available values are as follows:
**1 * 2**: indicates a grid with one row and two columns.
**2 * 2**: indicates a grid with two rows and two columns.
**2 * 4**: indicates a grid with two rows and four columns.
**4 * 4**: indicates a grid with four rows and four columns.| String array| No | - | defaultDimension | Default grid style of the widget. The value must be available in the **supportDimensions** array of the widget.| String | No | - | updateEnabled | Whether the widget can be updated periodically. Available values are as follows:
**true**: The widget can be updated periodically, depending on the update way you select, either at a specified interval (**updateDuration**) or at the scheduled time (**scheduledUpdateTime**). **updateDuration** is recommended.
**false**: The widget cannot be updated periodically.| Boolean | No | - | scheduledUpdateTime | Scheduled time to update the widget. The value is in 24-hour format and accurate to minute.
This parameter has a lower priority than **updateDuration**. If both are specified, the value specified by **updateDuration** is used.| String | Yes (initial value: **0:0**) | - | updateDuration | Interval to update the widget. The value is a natural number, in the unit of 30 minutes.
If the value is **0**, this field does not take effect.
If the value is a positive integer ***N***, the interval is calculated by multiplying ***N*** and 30 minutes.
This parameter has a higher priority than **scheduledUpdateTime**. If both are specified, the value specified by **updateDuration** is used.| Number | Yes (initial value: **0**) | - | formConfigAbility | Link to a specific page of the application. The value is a URI. | String | Yes (initial value: left empty) | - | formVisibleNotify | Whether the widget is allowed to use the widget visibility notification. | String | Yes (initial value: left empty) | - | metaData | Metadata of the widget. This field contains the array of the **customizeData** field. | Object | Yes (initial value: left empty) | - - A configuration example is as follows: - - ```json - { - "forms": [{ - "name": "widget", - "description": "This is a widget.", - "src": "./js/widget/pages/index/index", - "window": { - "autoDesignWidth": true, - "designWidth": 720 - }, - "isDefault": true, - "colorMode": "auto", - "supportDimensions": ["2*2"], - "defaultDimension": "2*2", - "updateEnabled": true, - "scheduledUpdateTime": "10:30", - "formConfigAbility": "ability://ohos.samples.FormApplication.MainAbility" - }] - } - ``` - - -### Persistently Storing Widget Data - -Mostly, the widget provider is started only when it needs to obtain information about a widget. The Widget Manager supports multi-instance management and uses the widget ID to identify an instance. If the widget provider supports widget data modification, it must persistently store the data based on the widget ID, so that it can access the data of the target widget when obtaining, updating, or starting the widget. - -```javascript - onCreate(want) { - console.log('FormAbility onCreate'); - - let formId = want.parameters["ohos.extra.param.key.form_identity"]; - let formName = want.parameters["ohos.extra.param.key.form_name"]; - let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"]; - // Persistently store widget data for subsequent use, such as widget instance retrieval or update. - // The storeFormInfo API is not implemented here. - storeFormInfo(formId, formName, tempFlag, want); - - let obj = { - "title": "titleOnCreate", - "detail": "detailOnCreate" - }; - let formData = formBindingData.createFormBindingData(obj); - return formData; - } -``` - -You should override **onDestroy** to delete widget data. - -```javascript - onDestroy(formId) { - console.log('FormAbility onDestroy'); - - // You need to implement the code for deleting the persistent widget data. - // The deleteFormInfo API is not implemented here. - deleteFormInfo(formId); - } -``` - -For details about the persistence method, see [Lightweight Data Store Development](../database/database-preference-guidelines.md). - -Note that the **Want** passed by the widget host to the widget provider contains a temporary flag, indicating whether the requested widget is a temporary one. - -- Normal widget: a widget that will be persistently used by the widget host - -- Temporary widget: a widget that is temporarily used by the widget host - -Data of a temporary widget is not persistently stored. If it is deleted from the Widget Manager due to exceptions, such as crash of the widget framework, the widget provider will not be notified of which widget is deleted, and still keeps the data. In light of this, the widget provider should implement data clearing. If the widget host successfully converts a temporary widget into a normal one, the widget provider should also process the widget ID and store the data persistently. This prevents the widget provider from deleting the widget data when clearing temporary widgets. - -### Updating Widget Data - -When a widget application initiates a data update upon a scheduled or periodic update, the application obtains the latest data and calls **updateForm** to update the widget. The sample code is as follows: - -```javascript -onUpdate(formId) { - // To support scheduled update, periodic update, or update requested by the widget host, override this method for widget data update. - console.log('FormAbility onUpdate'); - let obj = { - "title": "titleOnUpdate", - "detail": "detailOnUpdate" - }; - let formData = formBindingData.createFormBindingData(obj); - // Call the updateForm method to update the widget. Only the data passed through the input parameter is updated. Other information remains unchanged. - formProvider.updateForm(formId, formData).catch((error) => { - console.log('FormAbility updateForm, error:' + JSON.stringify(error)); - }); -} -``` - -### Developing the Widget UI Page - -You can use HML, CSS, and JSON to develop the UI page for a JavaScript-programmed widget. - -> **NOTE** -> -> Currently, only the JavaScript-based web-like development paradigm can be used to develop the widget UI. - - - In the HML file: - ```html -
- -
- -
-
- {{title}} - {{detail}} -
-
-
- ``` - - - In the CSS file: - - ```css -.container { - flex-direction: column; - justify-content: center; - align-items: center; -} - -.bg-img { - flex-shrink: 0; - height: 100%; -} - -.container-inner { - flex-direction: column; - justify-content: flex-end; - align-items: flex-start; - height: 100%; - width: 100%; - padding: 12px; -} - -.title { - font-size: 19px; - font-weight: bold; - color: white; - text-overflow: ellipsis; - max-lines: 1; -} - -.detail_text { - font-size: 16px; - color: white; - opacity: 0.66; - text-overflow: ellipsis; - max-lines: 1; - margin-top: 6px; -} - ``` - - - In the JSON file: - ```json - { - "data": { - "title": "TitleDefault", - "detail": "TextDefault" - }, - "actions": { - "routerEvent": { - "action": "router", - "abilityName": "MainAbility", - "params": { - "message": "add detail" - } - } - } - } - ``` - -Now you've got a widget shown below. - -![fa-form-example](figures/fa-form-example.png) - -### Developing Widget Events - -You can set router and message events for components on a widget. The router event applies to ability redirection, and the message event applies to custom click events. The key steps are as follows: - -1. Set **onclick** in the HML file to **routerEvent** or **messageEvent**, depending on the **actions** settings in the JSON file. -2. For the router event, set the following attributes: - - **action**: **"router"**. - - **abilityName**: target ability name, for example, **MainAbility**, which is the default main ability name in DevEco Studio for the stage model. - - **params**: custom parameters of the target ability. Set them as required. The value can be obtained from **parameters** in **want** used for starting the target ability. For example, in the lifecycle function **onCreate** of the main ability in the stage model, you can obtain **want** and its **parameters** field. -3. For the message event, set the following attributes: - - **action**: **"message"**. - - **params**: custom parameters of the message event. Set them as required. The value can be obtained from **message** in the widget lifecycle function **onEvent**. - -The following is an example: - - - In the HML file: - ```html -
- -
- -
-
- {{title}} - {{detail}} -
-
-
- ``` - - - In the JSON file: - ```json - { - "data": { - "title": "TitleDefault", - "detail": "TextDefault" - }, - "actions": { - "routerEvent": { - "action": "router", - "abilityName": "MainAbility", - "params": { - "message": "add detail" - } - }, - "messageEvent": { - "action": "message", - "params": { - "message": "add detail" - } - } - } - } - ``` \ No newline at end of file diff --git a/en/application-dev/ability/stage-serviceextension.md b/en/application-dev/ability/stage-serviceextension.md deleted file mode 100644 index 0d634ebe67ef9e332f658a0efb0f7ffdb0e1f2b7..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/stage-serviceextension.md +++ /dev/null @@ -1,74 +0,0 @@ -# Service Extension Ability Development - -## When to Use -`ExtensionAbility` is the base class of the new Extension component in the stage model. It is used to process missions without UIs. The lifecycle of an Extension ability is simple and does not involve foreground or background states. `ServiceExtensionAbility` is extended from `ExtensionAbility`. - -You can customize a class that inherits from `ServiceExtensionAbility` and override the lifecycle callbacks in the base class to perform service logic operations during the initialization, connection, and disconnection processes. - -## Available APIs - -**Table 1** ServiceExtensionAbility lifecycle APIs -|API|Description| -|:------|:------| -|onCreate(want: Want): void|Called for the initialization when `startAbility` or `connectAbility` is invoked for a given ability for the first time.| -|onRequest(want: Want, startId: number): void|Called each time `startAbility` is invoked for a given ability. The initial value of `startId` is `1`, and the value is incremented by one each time `startAbility` is invoked for that ability.| -|onConnect(want: Want): rpc.RemoteObject|Called when `connectAbility` is invoked for a given ability. This callback is not invoked for repeated calling of `connectAbility` for a specific ability. However, it will be invoked unless `connectAbility` is called after the ability has been disconnected using `disconnectAbility`. The returned result is a `RemoteObject`.| -|onDisconnect(want: Want): void|Called when `disconnectAbility` is called for a given ability. If the Extension ability is started by `connectAbility` and is not bound to other applications, the `onDestroy` callback will also be triggered to destroy the Extension ability.| -|onDestroy(): void|Called when `terminateSelf` is invoked to terminate the ability.| - - -## Constraints - -OpenHarmony does not support creation of a Service Extension ability for third-party applications. - - -## How to Develop - -1. Declare the Service Extension ability in the `module.json5` file by setting its `type` attribute to `service`. The following is a configuration example of the `module.json5` file: - - - ```json - "extensionAbilities":[{ - "name": "ServiceExtAbility", - "icon": "$media:icon", - "description": "service", - "type": "service", - "visible": true, - "srcEntrance": "./ets/ServiceExtAbility/ServiceExtAbility.ts" - }] - ``` - - -2. Customize a class that inherits from `ServiceExtensionAbility` in the .ts file in the directory where the Service Extension ability is defined (`entry\src\main\ets\ServiceExtAbility\ServiceExtAbility.ts` by default) and override the lifecycle callbacks of the base class. The code sample is as follows: - - ```js - import ServiceExtensionAbility from '@ohos.application.ServiceExtensionAbility' - import rpc from '@ohos.rpc' - - class StubTest extends rpc.RemoteObject { - constructor(des) { - super(des); - } - onRemoteRequest(code, data, reply, option) { - } - } - - class ServiceExtAbility extends ServiceExtensionAbility { - onCreate(want) { - console.log('onCreate, want:' + want.abilityName); - } - onRequest(want, startId) { - console.log('onRequest, want:' + want.abilityName); - } - onConnect(want) { - console.log('onConnect , want:' + want.abilityName); - return new StubTest("test"); - } - onDisconnect(want) { - console.log('onDisconnect, want:' + want.abilityName); - } - onDestroy() { - console.log('onDestroy'); - } - } - ``` \ No newline at end of file diff --git a/en/application-dev/ability/wantagent.md b/en/application-dev/ability/wantagent.md deleted file mode 100644 index 5a85bab15b8422aaabb0a173ad888126e08fc038..0000000000000000000000000000000000000000 --- a/en/application-dev/ability/wantagent.md +++ /dev/null @@ -1,88 +0,0 @@ -# WantAgent Development -## When to Use -The **WantAgent** class encapsulates want information that specifies a particular action, which can be starting an ability or publishing a common event. You can either call **wantAgent.trigger** to trigger a **WantAgent** directly or add a **WantAgent** to a notification so that it will be triggered when users tap the notification. - - - -## Available APIs -| API | Description| -| ---------------------------------------------------------------------------------------------- | ----------- | -| getWantAgentInfo(info: WantAgentInfo, callback: AsyncCallback\) | Creates a **WantAgent** object. This API uses an asynchronous callback to return the result.| -| getWantAgent(info: WantAgentInfo): Promise\ | Creates a **WantAgent** object. This API uses a promise to return the result.| -| trigger(agent: WantAgent, triggerInfo: TriggerInfo, callback?: Callback\) | Triggers a **WantAgent** object.| - -## How to Develop -1. Import the **WantAgent** module. - - ``` - import wantAgent from '@ohos.wantAgent'; - ``` - -2. Create a **WantAgentInfo** object that will be used for starting an ability. For details about the data types and parameters of **WantAgentInfo**, see [WantAgent](../reference/apis/js-apis-wantAgent.md#wantagentinfo). - - ``` - private wantAgentObj = null // Save the WantAgent object created. It will be used to complete the trigger operations. - - // wantAgentInfo - var wantAgentInfo = { - wants: [ - { - deviceId: "", - bundleName: "com.example.test", - abilityName: "com.example.test.MainAbility", - action: "", - entities: [], - uri: "", - parameters: {} - } - ], - operationType: wantAgent.OperationType.START_ABILITY, - requestCode: 0, - wantAgentFlags:[wantAgent.WantAgentFlags.CONSTANT_FLAG] - } - ``` - -3. Create a **WantAgentInfo** object for publishing a common event. - - ``` - private wantAgentObj = null // Save the WantAgent object created. It will be used to complete the trigger operations. - - // wantAgentInfo - var wantAgentInfo = { - wants: [ - { - action: "event_name", // Set the action name. - parameters: {} - } - ], - operationType: wantAgent.OperationType.SEND_COMMON_EVENT, - requestCode: 0, - wantAgentFlags:[wantAgent.WantAgentFlags.CONSTANT_FLAG] - } - ``` - -4. Create a **WantAgent** object and save the returned **wantAgentObj** for subsequent trigger operations. - - ``` - // Create a WantAgent object. - wantAgent.getWantAgent(wantAgentInfo, (err, wantAgentObj) => { - if (err.code) { - console.error("[WantAgent]getWantAgent err=" + JSON.stringify(err)) - } else { - console.log("[WantAgent]getWantAgent success") - this.wantAgentObj = wantAgentObj - } - }) - ``` - -5. Trigger the **WantAgent** object. - - ``` - // Trigger the WantAgent object. - var triggerInfo = { - code:0 - } - wantAgent.trigger(wantAgentObj, triggerInfo, (completeData) => { - console.log("[WantAgent]getWantAgent success, completeData: ", + JSON.stringify(completeData)) - }) - ``` diff --git a/en/application-dev/application-models/Readme-EN.md b/en/application-dev/application-models/Readme-EN.md new file mode 100644 index 0000000000000000000000000000000000000000..a9473b7f6c2d0fb75e160cafdd1fb94b43633fa7 --- /dev/null +++ b/en/application-dev/application-models/Readme-EN.md @@ -0,0 +1,2 @@ +# Application Models + diff --git a/en/application-dev/application-test/Readme.md b/en/application-dev/application-test/Readme.md new file mode 100644 index 0000000000000000000000000000000000000000..7d465c149d73288be0687b15269152b743509432 --- /dev/null +++ b/en/application-dev/application-test/Readme.md @@ -0,0 +1,6 @@ +# Application Test + +- [arkXtest User Guide](arkxtest-guidelines.md) +- [SmartPerf User Guide](smartperf-guidelines.md) +- [wukong User Guide](wukong-guidelines.md) + diff --git a/en/application-dev/application-test/arkxtest-guidelines.md b/en/application-dev/application-test/arkxtest-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..ce7a28154635b724d127a50af801c74f84607402 --- /dev/null +++ b/en/application-dev/application-test/arkxtest-guidelines.md @@ -0,0 +1,270 @@ +# arkXtest User Guide + + +## Overview + +To accelerate test automation of OpenHarmony, arkXtest — an automated test framework that supports both the JavaScript (JS) and TypeScript (TS) programming languages — is provided. + +In this document you will learn about the key functions of arkXtest and how to use it to perform unit testing on application or system APIs and to write UI automated test scripts. + + +### Introduction + +arkXtest is part of the OpenHarmony toolkit and provides basic capabilities of writing and running OpenHarmony automated test scripts. In terms of test script writing, arkXtest offers a wide range of APIs, including basic process APIs, assertion APIs, and APIs related to UI operations. In terms of test script running, arkXtest offers such features as identifying, scheduling, and executing test scripts, as well as summarizing test script execution results. + + +### Principles + +arkXtest is divided into two parts: unit test framework and UI test framework. + +- Unit Test Framework + + As the backbone of arkXtest, the unit test framework offers such features as identifying, scheduling, and executing test scripts, as well as summarizing test script execution results. The figure below shows the main functions of the unit test framework. + + ![](figures/UnitTest.PNG) + + The following figure shows the basic unit test process. To start the unit test framework, run the **aa test** command. + + ![](figures/TestFlow.PNG) + +- UI Testing Framework + + The UI test framework provides [UiTest APIs](../reference/apis/js-apis-uitest.md) for you to call in different test scenarios. The test scripts are executed on top of the unit test framework mentioned above. + + The figure below shows the main functions of the UI test framework. + + ![](figures/Uitest.PNG) + + +### Limitations and Constraints + +- The features of the UI test framework are available only in OpenHarmony 3.1 and later versions. +- The feature availability of the unit test framework varies by version. For details about the mappings between the features and versions, see [arkXtest](https://gitee.com/openharmony/testfwk_arkxtest/blob/master/README_en.md). + + +## Environment preparations + +### Environment Requirements + +Software for writing test scripts: DevEco Studio 3.0 or later + +Hardware for running test scripts: PC connected to a OpenHarmony device, such as the RK3568 development board + +### Setting Up the Environment + +[Download DevEco Studio](https://developer.harmonyos.com/cn/develop/deveco-studio#download) and set it up as instructed on the official website. + + +## Creating a Test Script + +1. Open DevEco Studio and create a project, where the **ohos** directory is where the test script is located. +2. Open the .ets file of the module to be tested in the project directory. Move the cursor to any position in the code, and then right-click and choose **Show Context Actions** > **Create Ohos Test** or press **Alt+Enter** and choose **Create Ohos Test** to create a test class. + +## Writing a Unit Test Script + +```TS +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium' +import abilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' + +const delegator = abilityDelegatorRegistry.getAbilityDelegator() +export default function abilityTest() { + describe('ActsAbilityTest', function () { + it('testUiExample',0, async function (done) { + console.info("uitest: TestUiExample begin"); + //start tested ability + await delegator.executeShellCommand('aa start -b com.ohos.uitest -a MainAbility').then(result =>{ + console.info('Uitest, start ability finished:' + result) + }).catch(err => { + console.info('Uitest, start ability failed: ' + err) + }) + await sleep(1000); + //check top display ability + await delegator.getCurrentTopAbility().then((Ability)=>{ + console.info("get top ability"); + expect(Ability.context.abilityInfo.name).assertEqual('MainAbility'); + }) + done(); + }) + + function sleep(time) { + return new Promise((resolve) => setTimeout(resolve, time)); + } + }) +} +``` + +The unit test script must contain the following basic elements: + +1. Import of the dependency package so that the dependent test APIs can be used. + +2. Test code, mainly about the related logic, such as API invoking. + +3. Invoking of the assertion APIs and setting of checkpoints. If there is no checkpoint, the test script is considered as incomplete. + +## Writing a UI Test Script + +You write a UI test script based on the unit test framework, adding the invoking of APIs provided by the UI test framework to implement the corresponding test logic. + +In this example, the UI test script is written based on the preceding unit test script. First, add the dependency package, as shown below: + +```js +import {UiDriver,BY,UiComponent,MatchPattern} from '@ohos.uitest' +``` + +Then, write specific test code. Specifically, implement the click action on the started application page and add checkpoint check cases. + +```js +export default function abilityTest() { + describe('ActsAbilityTest', function () { + it('testUiExample',0, async function (done) { + console.info("uitest: TestUiExample begin"); + //start tested ability + await delegator.executeShellCommand('aa start -b com.ohos.uitest -a MainAbility').then(result =>{ + console.info('Uitest, start ability finished:' + result) + }).catch(err => { + console.info('Uitest, start ability failed: ' + err) + }) + await sleep(1000); + //check top display ability + await delegator.getCurrentTopAbility().then((Ability)=>{ + console.info("get top ability"); + expect(Ability.context.abilityInfo.name).assertEqual('MainAbility'); + }) + //ui test code + //init uidriver + var driver = await UiDriver.create(); + await driver.delayMs(1000); + //find button by text 'Next' + var button = await driver.findComponent(BY.text('Next')); + //click button + await button.click(); + await driver.delayMs(1000); + //check text + await driver.assertComponentExist(BY.text('after click')); + await driver.pressBack(); + done(); + }) + + function sleep(time) { + return new Promise((resolve) => setTimeout(resolve, time)); + } + }) +} +``` + +## Running the Test Script + +You can run a test script in DevEco Studio in any of the following modes: + +- Test package level: All test cases in the test package are executed. +- Test suite level: All test cases defined in the **describe** method are executed. +- Test method level: The specified **it** method, that is, a single test case, is executed. + +![](figures/Execute.PNG) + +## Viewing the Test Result + +After the test is complete, you can view the test result in DevEco Studio, as shown in the following figure. + +![](figures/TestResult.PNG) + +## FAQs + +### FAQs About Unit Test Cases + +#### The logs in the test case are printed after the test case result + +**Problem** + +The logs added to the test case are displayed after the test case execution, rather than during the test case execution. + +**Possible Causes** + +More than one asynchronous interface is called in the test case.
In principle, logs in the test case are printed before the test case execution is complete. + + **Solution** + +If more than one asynchronous interface is called, you are advised to encapsulate the interface invoking into the promise mode + +#### Error "fail to start ability" is reported during test case execution + +**Problem** + +When a test case is executed, the console returns the error message "fail to start ability". + +**Possible Causes** + +An error occurs during the packaging of the test package, and the test framework dependency file is not included in the test package. + +**Solution** + +Check whether the test package contains the **OpenHarmonyTestRunner.abc** file. If the file does not exist, rebuild and pack the file and perform the test again. + +#### Test case execution timeout + +**Problem** + +After the test case execution is complete, the console displays the error message "execute time XXms", indicating that the case execution times out. + +**Possible Causes** + +1. The test case is executed through an asynchronous interface, but the **done** function is not executed during the execution. As a result, the test case execution does not end until it times out. +2. The time taken for API invocation is longer than the timeout interval set for test case execution. + +**Solution** + +1. Check the code logic of the test case to ensure that the **done** function is executed even if the assertion fails. + +2. Modify the case execution timeout settings under **Run/Debug Configurations** in DevEco Studio. + +### FAQs About UI Test Cases + +#### The failure log contains "Get windows failed/GetRootByWindow failed" + +**Problem** + +The UI test case fails to be executed. The HiLog file contains the error message "Get windows failed/GetRootByWindow failed". + +**Possible Causes** + +The ArkUI feature is disabled. As a result, the control tree information on the test page is not generated. + +**Solution** + +Run the following command, restart the device, and execute the test case again: + +```shell +hdc shell param set persist.ace.testmode.enabled 1 +``` + +#### The failure log contains "uitest-api dose not allow calling concurrently" + +**Problem** + +The UI test case fails to be executed. The HiLog file contains the error message "uitest-api dose not allow calling concurrently". + +**Possible Causes** + +1. In the test case, the **await** operator is not added to the asynchronous interface provided by the UI test framework. + +2. The UI test case is executed in multiple processes. As a result, multiple UI test processes are started. The framework does not support multi-process invoking. + +**Solution** + +1. Check the case implementation and add the **await** operator to the asynchronous interface invoking. + +2. Do not execute UI test cases in multiple processes. + +#### The failure log contains "dose not exist on current UI! Check if the UI has changed after you got the widget object" + +**Problem** + +The UI test case fails to be executed. The HiLog file contains the error message "dose not exist on current UI! Check if the UI has changed after you got the widget object". + +**Possible Causes** + +After the target component is found in the code of the test case, the device UI changes. As a result, the found component is lost and the emulation operation cannot be performed. + +**Solution** + +Run the UI test case again. diff --git a/en/application-dev/application-test/figures/Execute.PNG b/en/application-dev/application-test/figures/Execute.PNG new file mode 100644 index 0000000000000000000000000000000000000000..90dcb55338ad473d29557e4c761801b16c770d45 Binary files /dev/null and b/en/application-dev/application-test/figures/Execute.PNG differ diff --git a/en/application-dev/application-test/figures/SmartPerfStru.png b/en/application-dev/application-test/figures/SmartPerfStru.png new file mode 100644 index 0000000000000000000000000000000000000000..24d203f938891e5a2b73c066776c62b1065fd064 Binary files /dev/null and b/en/application-dev/application-test/figures/SmartPerfStru.png differ diff --git a/en/application-dev/application-test/figures/TestFlow.PNG b/en/application-dev/application-test/figures/TestFlow.PNG new file mode 100644 index 0000000000000000000000000000000000000000..0b79c7e8c34e78397f1c442208de5dbff9c2e91e Binary files /dev/null and b/en/application-dev/application-test/figures/TestFlow.PNG differ diff --git a/en/application-dev/application-test/figures/TestResult.PNG b/en/application-dev/application-test/figures/TestResult.PNG new file mode 100644 index 0000000000000000000000000000000000000000..300266842efab6da7a4f7469ab8c9e890f238b89 Binary files /dev/null and b/en/application-dev/application-test/figures/TestResult.PNG differ diff --git a/en/application-dev/application-test/figures/Uitest.PNG b/en/application-dev/application-test/figures/Uitest.PNG new file mode 100644 index 0000000000000000000000000000000000000000..a9ff5b9d831b4abe1767219dfa8e2fffc5c2e3f8 Binary files /dev/null and b/en/application-dev/application-test/figures/Uitest.PNG differ diff --git a/en/application-dev/application-test/figures/UnitTest.PNG b/en/application-dev/application-test/figures/UnitTest.PNG new file mode 100644 index 0000000000000000000000000000000000000000..d55de62d830df9cfdf345552c54dbf4196564ef6 Binary files /dev/null and b/en/application-dev/application-test/figures/UnitTest.PNG differ diff --git a/en/application-dev/application-test/figures/wukongRandomTest.png b/en/application-dev/application-test/figures/wukongRandomTest.png new file mode 100644 index 0000000000000000000000000000000000000000..a8164620f94f8d4ec61e22e53eb655888ce15050 Binary files /dev/null and b/en/application-dev/application-test/figures/wukongRandomTest.png differ diff --git a/en/application-dev/application-test/figures/wukongRandomTestFlow.png b/en/application-dev/application-test/figures/wukongRandomTestFlow.png new file mode 100644 index 0000000000000000000000000000000000000000..d2355d66557b2b3ce4066691adbe7cce7eb1a5f2 Binary files /dev/null and b/en/application-dev/application-test/figures/wukongRandomTestFlow.png differ diff --git a/en/application-dev/application-test/figures/wukongSpecialTest.png b/en/application-dev/application-test/figures/wukongSpecialTest.png new file mode 100644 index 0000000000000000000000000000000000000000..0f4362da3f8c8cd7b40582acdb443a72434efebf Binary files /dev/null and b/en/application-dev/application-test/figures/wukongSpecialTest.png differ diff --git a/en/application-dev/application-test/smartperf-guidelines.md b/en/application-dev/application-test/smartperf-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..91b6cf44ef419487de7b435e42d26199c3b088d0 --- /dev/null +++ b/en/application-dev/application-test/smartperf-guidelines.md @@ -0,0 +1,75 @@ +# SmartPerf User Guide + +## Overview + +Performance testing helps developers detect the performance bottlenecks and deliver quality applications that meet user expectations. For this reason, SmartPerf, a performance testing tool specially designed for OpenHarmony developers, is provided. + +## Introduction + +SmartPerf is a reliable, easy-to-use performance and power consumption test tool built for the OpenHarmony system. It provides KPIs with test value details that help you measure the performance and power consumption of your application, such as FPS, CPU, GPU, and Ftrace. + +You can use SmartPerf in two modes: visualized operation mode (SmartPerf-Device) and command-line shell mode (SmartPerf-Daemon). SmartPerf-Device supports visualized operations and floating window based operations (such as data collection control and real-time data display). SmartPerf-Daemon is applicable to devices without screens and devices with high tolerance regarding performance, for example, Hi3568. + +## Principles + +SmartPerf come with SmartPerf-Device and SmartPerf-Daemon. SmartPerf-Device sends data requests for KPIs (such as FPS, RAM, and Trace) through messages to SmartPerf-Daemon, which then collects and sends back data as requested, and displays the received data. SmartPerf-Daemon also allows on-demand data collection through hell commands. The figure below demonstrates the main functions of SmartPerf. + +![SmartPerf](figures/SmartPerfStru.png) + +## Constraints + +- SmartPerf-Device and SmartPerf-Daemon are pre-installed in version 3.2 and later versions. +- SmartPerf-Device requires a screen to work correctly. + +## Environment Preparations + +To run SmartPerf-Daemon, you must connect the PC to an OpenHarmony device, such as the RK3568 development board. + +## Performing Performance Testing + +**Using SmartPerf-Device** + +In the screenshots below, the RK3568 development board is used as an example. + +1. Set the application for which you want to collect data. + + Start SmartPerf-Device. On the home screen, select the test application and test indicators, and touch **Start Test**. + +2. Control the data collection process from the floating window. + + To start collection, touch **Start** in the floating window. To pause, touch the timer in the floating window to pause data collection. To resume, touch the timer again. To view the collected data in real time, double-touch the timer. To stop, touch and hold the timer. You can drag the floating window to anywhere you like. + + +3. View the report. + + Touch **Report** to view the test report list. Touch **Report List** to view details about test indicators. + +**Using SmartPerf-Daemon** + +1. Access the shell and run the following command to view the help information: +``` +:# SP_daemon --help +``` +2. Run the collection commands. +``` +:# SP_daemon -N 2 -PKG com.ohos.contacts -c -g -t -p -r +``` + +**Collection Commands** + +| Command | Function |Mandatory| +| :-----| :--------------------- |:-----| +| -N | Set the number of collection times. |Yes| +| -PKG | Set the package name. | No| +| -PID | Sets the PID of a process (applicable to RAM).|No| +| -c | Set whether to collect CPU data. | No| +| -g | Set whether to collect GPU data. |No| +| -f | Set whether to collect FPS data. |No| +| -t | Set whether to collect temperature data. |No| +| -p | Set whether to collect current data. |No| +| -r | Set whether to collect memory data. |No| + +The default output path of the test result is as follows: +``` +/data/local/tmp/data.csv +``` diff --git a/en/application-dev/application-test/wukong-guidelines.md b/en/application-dev/application-test/wukong-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..e10cb9fa1badd83bd244e70a1f4445afd7f085b7 --- /dev/null +++ b/en/application-dev/application-test/wukong-guidelines.md @@ -0,0 +1,113 @@ +# wukong User Guide + + +## Overview + +Stability testing is important in that it demonstrates how an application performs under stress. For this reason, wukong, a stability testing tool specially designed for OpenHarmony developers, is provided. + +In this document you will learn about the key functions of wukong and how to use it to perform stability testing. + +## Introduction + +wukong is part of the OpenHarmony toolkit and implements basic application stability test capabilities such as random event injection, component injection, exception capture, report generation, and data traversal of abilities. + +## Principles + +wukong mainly provides two types of tests: random test and special test. + +- Random test + + The random test is the staple service of wukong. It provides the basic startup, running, and result summary features, as shown below. + + ![](figures/wukongRandomTest.png) + + The following figure shows the basic running process of the random test, which depends on the **hdc** command. + + ![](figures/wukongRandomTestFlow.png) + +- Special test + + The special test provides a wide range of features: traversing the components of an application in sequence, recording and playback, and sleeping and waking up. + + The following figure shows the main features of the special test. + + ![](figures/wukongSpecialTest.png) + +For details about the test commands, see [wukong](https://gitee.com/openharmony/ostest_wukong/blob/master/README.md). + +## Constraints + +1. wukong is pre-installed in version 3.2 and later versions. + +2. In versions earlier than 3.2, you must build wukong separately and push it to the tested OpenHarmony device. The procedure is as follows: + How to build: + ``` + ./build.sh --product-name rk3568 --build-target wukong + ``` + How to push: + ``` + hdc_std shell mount -o rw,remount / + hdc_std file send wukong / + hdc_std shell chmod a+x /wukong + hdc_std shell mv /wukong /bin/ + ``` + +## Environment Preparations + +To run commands, connect the PC to an OpenHarmony device, such as the RK3568 development board. + +## Performing Stability Testing + +**Using wukong exec for Random Test** + +Access the shell and run the following random test command: +``` +# wukong exec -s 10 -i 1000 -a 0.28 -t 0.72 -c 100 +``` +Random test commands +| Command | Value | Description | +| -------------- | -------------- | ---------------------------------------------- | +| wukong exec | - | Works as the main command. | +| -s | 10 | Sets the random seed. The value 10 is the seed value. | +| -i | 1000 | Sets the application startup interval to 1000 ms.| +| -a | 0.28 | Sets the proportion of the random application startup test to 28%. | +| -t | 0.72 | Sets the proportion of the random touch test to 72%. | +| -c | 100 | Sets the number of execution times to 100. | + +**Using wukong special for Special Test** + +Access the shell and run the following commands to perform the sequential traversal test: +```bash +# wukong special -C [bundlename] -p +``` +Special test commands +| Command | Value | Description | +| -------------- |-------------- | ---------------------------------------------- | +| wukong special | - | Works as the main command. | +| -C [bundlename] |[bundlename] | Sets the bundle name of the application for the sequential traversal test. | +| -p | - | Indicates a screenshot. | + +## Viewing the Test Result + +After the test commands are executed, the test result is automatically generated. + +You can obtain the test result in the following directory: +``` +Before 2022/9/22: /data/local/wukong/report/xxxxxxxx_xxxxxx/ +Since 2022/9/22: /data/local/tmp/wukong/report/xxxxxxxx_xxxxxx/ +``` +>**NOTE** +> +>The folder for test reports is automatically generated. + +Content of the folder is described in the table below. +| Folder/File | Description | +| ------------------------------------ | ------------------ | +| exception/ | Stores exception files generated during the test.| +| screenshot/ | Stores screenshots of the sequential traversal test. | +| wukong_report.csv | Stores the test report summary. | + +You can view the wukong execution log in the path below: +``` +reports/xxxxxxxx_xxxxxx/wukong.log +``` diff --git a/en/application-dev/connectivity/Readme-EN.md b/en/application-dev/connectivity/Readme-EN.md index 16bf40cf8467bc805d3b485ca46d6f0fa295b3bc..578e2a3c56c8a1f6cce377eb39ef9a7756d74491 100755 --- a/en/application-dev/connectivity/Readme-EN.md +++ b/en/application-dev/connectivity/Readme-EN.md @@ -1,11 +1,11 @@ # Connectivity - Network Management - - [Network Management Overview](net-mgmt-overview.md) - - [HTTP Data Request](http-request.md) - - [WebSocket Connection](websocket-connection.md) - - [Socket Connection](socket-connection.md) + - [Network Management Overview](net-mgmt-overview.md) + - [HTTP Data Request](http-request.md) + - [WebSocket Connection](websocket-connection.md) + - [Socket Connection](socket-connection.md) - IPC & RPC - - [IPC & RPC Overview](ipc-rpc-overview.md) - - [IPC & RPC Development](ipc-rpc-development-guideline.md) - - [Subscribing to State Changes of a Remote Object](subscribe-remote-state.md) + - [IPC & RPC Overview](ipc-rpc-overview.md) + - [IPC & RPC Development](ipc-rpc-development-guideline.md) + - [Subscribing to State Changes of a Remote Object](subscribe-remote-state.md) diff --git a/en/application-dev/connectivity/http-request.md b/en/application-dev/connectivity/http-request.md index 6ddf26b87022c8bf098efc72de9ae4b4c0e28779..da1a7e1c517f284037a41a88e2167b6d1d2406aa 100644 --- a/en/application-dev/connectivity/http-request.md +++ b/en/application-dev/connectivity/http-request.md @@ -12,7 +12,7 @@ To use related APIs, you must declare the **ohos.permission.INTERNET** permissio For details about how to apply for permissions, see [Access Control Development](../security/accesstoken-guidelines.md). -The following table describes the related APIs. +The following table provides only a simple description of the related APIs. For details, see [API Reference](../reference/apis/js-apis-http.md). | API | Description | | ----------------------------------------- | --------------------------------------------------------- | diff --git a/en/application-dev/connectivity/ipc-rpc-development-guideline.md b/en/application-dev/connectivity/ipc-rpc-development-guideline.md index 1fddf868604e564e4b6a6701f8d3a8088c4d8326..0eeef8040da8abd9710f3996f0b5f2c65ecf71e2 100644 --- a/en/application-dev/connectivity/ipc-rpc-development-guideline.md +++ b/en/application-dev/connectivity/ipc-rpc-development-guideline.md @@ -10,7 +10,7 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat | Class/Interface | Function | Description | | --------------- | -------- | ----------- | -| IRemoteBroker | sptr AsObject() | Obtains the holder of a remote proxy object. This method must be implemented by the derived classes of **IRemoteBroker**. If you call this method on the stub, the **RemoteObject** is returned; if you call this method on the proxy, the proxy object is returned. | +| [IRemoteBroker](../reference/apis/js-apis-rpc.md#iremotebroker) | sptr AsObject() | Obtains the holder of a remote proxy object. This method must be implemented by the derived classes of **IRemoteBroker**. If you call this method on the stub, the **RemoteObject** is returned; if you call this method on the proxy, the proxy object is returned. | | IRemoteStub | virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) | Called to process a request from the proxy and return the result. Derived classes need to override this method. | | IRemoteProxy | | Service proxy classes are derived from the **IRemoteProxy** class. | @@ -25,10 +25,10 @@ IPC/RPC enables a proxy and a stub that run on different processes to communicat ``` class ITestAbility : public IRemoteBroker { public: - // DECLARE_INTERFACE_DESCRIPTOR is mandatory, and the input parameter is std::u16string. - DECLARE_INTERFACE_DESCRIPTOR(u"test.ITestAbility"); - int TRANS_ID_PING_ABILITY = 1; // Define the message code. - virtual int TestPingAbility(const std::u16string &dummy) = 0; // Define functions. + // DECLARE_INTERFACE_DESCRIPTOR is mandatory, and the input parameter is std::u16string. + DECLARE_INTERFACE_DESCRIPTOR(u"test.ITestAbility"); + int TRANS_ID_PING_ABILITY = 1; // Define the message code. + virtual int TestPingAbility(const std::u16string &dummy) = 0; // Define functions. }; ``` diff --git a/en/application-dev/database/database-datashare-guidelines.md b/en/application-dev/database/database-datashare-guidelines.md index 495f3b538b48b22d2d97f213d0e32189be799560..064c3e393fe27cedceb1f3f7d2d1e03b8ec22db6 100644 --- a/en/application-dev/database/database-datashare-guidelines.md +++ b/en/application-dev/database/database-datashare-guidelines.md @@ -52,9 +52,9 @@ Examples are given below. 3. Implement the data provider services. For example, implement data storage of the data provider by using a database, reading and writing files, or accessing the network. ```ts - let DB_NAME = "DB00.db"; - let TBL_NAME = "TBL00"; - let DDL_TBL_CREATE = "CREATE TABLE IF NOT EXISTS " + const DB_NAME = "DB00.db"; + const TBL_NAME = "TBL00"; + const DDL_TBL_CREATE = "CREATE TABLE IF NOT EXISTS " + TBL_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, isStudent BOOLEAN, Binary BINARY)"; @@ -132,9 +132,9 @@ Examples are given below. 1. Import the dependencies. ```ts - import Ability from '@ohos.application.Ability' - import dataShare from '@ohos.data.dataShare' - import dataSharePredicates from '@ohos.data.dataSharePredicates' + import Ability from '@ohos.application.Ability'; + import dataShare from '@ohos.data.dataShare'; + import dataSharePredicates from '@ohos.data.dataSharePredicates'; ``` 2. Define the URI string for communicating with the data provider. @@ -164,29 +164,25 @@ Examples are given below. ```ts // Construct a piece of data. - var valuesBucket = { "name": "ZhangSan", "age": 21, "isStudent": false, "Binary": new Uint8Array([1, 2, 3]) }; - var updateBucket = { "name": "LiSi", "age": 18, "isStudent": true, "Binary": new Uint8Array([1, 2, 3]) }; - let da = new dataSharePredicates.DataSharePredicates(); - var valArray = new Array("*"); - let people = new Array( - { "name": "LiSi", "age": 41, "Binary": ar }, - { "name": "WangWu", "age": 21, "Binary": arr }, - { "name": "ZhaoLiu", "age": 61, "Binary": arr }); + let valuesBucket = { "name": "ZhangSan", "age": 21, "isStudent": false, "Binary": new Uint8Array([1, 2, 3]) }; + let updateBucket = { "name": "LiSi", "age": 18, "isStudent": true, "Binary": new Uint8Array([1, 2, 3]) }; + let predicates = new dataSharePredicates.DataSharePredicates(); + let valArray = new Array("*"); // Insert a piece of data. dsHelper.insert(dseUri, valuesBucket, (err, data) => { console.log("dsHelper insert result: " + data); }); - // Delete data. - dsHelper.delete(dseUri, da, (err, data) => { - console.log("dsHelper delete result: " + data); - }); // Update data. - dsHelper.update(dseUri, da, updateBucket, (err, data) => { + dsHelper.update(dseUri, predicates, updateBucket, (err, data) => { console.log("dsHelper update result: " + data); }); // Query data. - dsHelper.query(dseUri, da, valArray, (err, data) => { + dsHelper.query(dseUri, predicates, valArray, (err, data) => { console.log("dsHelper query result: " + data); }); + // Delete data. + dsHelper.delete(dseUri, predicates, (err, data) => { + console.log("dsHelper delete result: " + data); + }); ``` diff --git a/en/application-dev/database/database-datashare-overview.md b/en/application-dev/database/database-datashare-overview.md index f603c4dd54840118471cba6c344de58121577d57..019adeb3fa6850ed5407e0107d5996054ef11de7 100644 --- a/en/application-dev/database/database-datashare-overview.md +++ b/en/application-dev/database/database-datashare-overview.md @@ -22,7 +22,7 @@ Before you get started, familiarize yourself with the following concepts: An application that accesses the data or services provided by a data provider. It is also called a client. -- Value bucket (**ValuesBucket**) +- **ValuesBucket** One or more data records stored in the form of key-value (KV) pairs. The keys are of the string type. The values can be of the number, string, Boolean, or Unit8Array type. diff --git a/en/application-dev/database/database-distributedobject-overview.md b/en/application-dev/database/database-distributedobject-overview.md index 80985ed39b8c91a5c9635e0be8fd00f4be2da702..9fb93eba7c13f85da0cdccb9036df26e4d8d8ce0 100644 --- a/en/application-dev/database/database-distributedobject-overview.md +++ b/en/application-dev/database/database-distributedobject-overview.md @@ -12,7 +12,7 @@ The distributed data object management framework provides object-oriented in-mem - **Distributed data object** - A distributed data object is an encapsulation of the JS object type. Each distributed data object instance creates a data table in the in-memory database. The in-memory databases created for different applications are isolated from each other. Reading data from and writing data to a distributed data object are mapped to the **put** and **get** operations in the corresponding database, respectively. + A distributed data object is an encapsulation of the JS object type. Each distributed data object instance creates a data table in the in-memory database. The in-memory databases created for different applications are isolated from each other. Reading data from and writing data to a distributed data object are mapped to the **get** and **put** operations in the corresponding database, respectively. The distributed data object can be in the following states in its lifecycle: diff --git a/en/application-dev/database/database-mdds-guidelines.md b/en/application-dev/database/database-mdds-guidelines.md index 2205df9ceffb51c3c6cb7816f6d11784ba532b20..73f785de4ddccaa1e10c6049066a5f3908d85fc6 100644 --- a/en/application-dev/database/database-mdds-guidelines.md +++ b/en/application-dev/database/database-mdds-guidelines.md @@ -6,20 +6,20 @@ The Distributed Data Service (DDS) implements synchronization of application dat ## Available APIs -For details about the APIs, see [Distributed Data Management](../reference/apis/js-apis-distributed-data.md). +For details about the APIs, see [Distributed KV Store](../reference/apis/js-apis-distributedKVStore.md). **Table 1** APIs provided by the DDS -| API | Description | -| ------------------------------------------------------------ | ----------------------------------------------- | -| createKVManager(config: KVManagerConfig, callback: AsyncCallback<KVManager>): void
createKVManager(config: KVManagerConfig): Promise<KVManager> | Creates a **KVManager** object for database management.| -| getKVStore<TextendsKVStore>(storeId: string, options: Options, callback: AsyncCallback<T>): void
getKVStore<TextendsKVStore>(storeId: string, options: Options): Promise<T> | Obtains a KV store with the specified **Options** and **storeId**.| -| put(key: string, value: Uint8Array\|string\|number\|boolean, callback: AsyncCallback<void>): void
put(key: string, value: Uint8Array\|string\|number\|boolean): Promise<void> | Inserts and updates data. | -| delete(key: string, callback: AsyncCallback<void>): void
delete(key: string): Promise<void> | Deletes data. | -| get(key: string, callback: AsyncCallback<Uint8Array\|string\|boolean\|number>): void
get(key: string): Promise<Uint8Array\|string\|boolean\|number> | Queries data. | -| on(event: 'dataChange', type: SubscribeType, observer: Callback<ChangeNotification>): void
on(event: 'syncComplete', syncCallback: Callback<Array<[string,number]>>): void | Subscribes to data changes in the KV store. | -| sync(deviceIdList: string[], mode: SyncMode, allowedDelayMs?: number): void | Triggers database synchronization in manual mode. | +| API | Description | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| createKVManager(config: KVManagerConfig, callback: AsyncCallback<KVManager>): void
createKVManager(config: KVManagerConfig): Promise<KVManager> | Creates a **KvManager** object for database management. | +| getKVStore<TextendsKVStore>(storeId: string, options: Options, callback: AsyncCallback<T>): void
getKVStore<TextendsKVStore>(storeId: string, options: Options): Promise<T> | Creates and obtains a KV store.| +| put(key: string, value: Uint8Array\|string\|number\|boolean, callback: AsyncCallback<void>): void
put(key: string, value: Uint8Array\|string\|number\|boolean): Promise<void> | Inserts and updates data. | +| delete(key: string, callback: AsyncCallback<void>): void
delete(key: string): Promise<void> | Deletes data. | +| get(key: string, callback: AsyncCallback<Uint8Array\|string\|boolean\|number>): void
get(key: string): Promise<Uint8Array\|string\|boolean\|number> | Queries data. | +| on(event: 'dataChange', type: SubscribeType, observer: Callback<ChangeNotification>): void
on(event: 'syncComplete', syncCallback: Callback<Array<[string,number]>>): void | Subscribes to data changes in the KV store. | +| sync(deviceIdList: string[], mode: SyncMode, allowedDelayMs?: number): void | Triggers database synchronization in manual mode. | ## How to Develop @@ -28,70 +28,105 @@ The following uses a single KV store as an example to describe the development p 1. Import the distributed data module. ```js - import distributedData from '@ohos.data.distributedData'; + import distributedKVStore from '@ohos.data.distributedKVStore'; ``` + 2. Apply for the required permission if data synchronization is required. Add the permission required (FA model) in the **config.json** file. The sample code is as follows: ```json - { - "module": { - "reqPermissions": [ - { - "name": "ohos.permission.DISTRIBUTED_DATASYNC" - } - ] - } - } + { + "module": { + "reqPermissions": [ + { + "name": "ohos.permission.DISTRIBUTED_DATASYNC" + } + ] + } + } ``` + For the apps based on the stage model, see [Declaring Permissions](../security/accesstoken-guidelines.md#stage-model). This permission must also be granted by the user when the application is started for the first time. The sample code is as follows: ```js + // FA model import featureAbility from '@ohos.ability.featureAbility'; - + function grantPermission() { - console.info('grantPermission'); - let context = featureAbility.getContext(); - context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) { - console.info(`result.requestCode=${result.requestCode}`) - - }) - console.info('end grantPermission'); + console.info('grantPermission'); + let context = featureAbility.getContext(); + context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666).then((data) => { + console.info('success: ${data}'); + }).catch((error) => { + console.info('failed: ${error}'); + }) } - + + grantPermission(); + + // Stage model + import Ability from '@ohos.application.Ability'; + + let context = null; + + function grantPermission() { + class MainAbility extends Ability { + onWindowStageCreate(windowStage) { + let context = this.context; + } + } + + let permissions = ['ohos.permission.DISTRIBUTED_DATASYNC']; + context.requestPermissionsFromUser(permissions).then((data) => { + console.log('success: ${data}'); + }).catch((error) => { + console.log('failed: ${error}'); + }); + } + grantPermission(); ``` -3. Create a **kvManager** instance based on the specified **kvManagerConfig** object. +3. Create a **KvManager** instance based on the specified **KvManagerConfig** object. 1. Create a **kvManagerConfig** object based on the application context. - 2. Create a **kvManager** instance. + 2. Create a **KvManager** instance. The sample code is as follows: ```js + // Obtain the context of the FA model. + import featureAbility from '@ohos.ability.featureAbility'; + let context = featureAbility.getContext(); + + // Obtain the context of the stage model. + import AbilityStage from '@ohos.application.Ability'; + let context = null; + class MainAbility extends AbilityStage{ + onWindowStageCreate(windowStage){ + context = this.context; + } + } + let kvManager; try { const kvManagerConfig = { bundleName: 'com.example.datamanagertest', - userInfo: { - userId: '0', - userType: distributedData.UserType.SAME_USER_ID - } + context:context, } - distributedData.createKVManager(kvManagerConfig, function (err, manager) { + distributedKVStore.createKVManager(kvManagerConfig, function (err, manager) { if (err) { - console.log("createKVManager err: " + JSON.stringify(err)); + console.error(`Failed to create KVManager.code is ${err.code},message is ${err.message}`); return; } - console.log("createKVManager success"); + console.log('Created KVManager successfully'); kvManager = manager; }); } catch (e) { - console.log("An unexpected error occurred. Error: " + e); + console.error(`An unexpected error occurred.code is ${e.code},message is ${e.message}`); } ``` @@ -110,34 +145,38 @@ The following uses a single KV store as an example to describe the development p encrypt: false, backup: false, autoSync: false, - kvStoreType: distributedData.KVStoreType.SINGLE_VERSION, - securityLevel: distributedData.SecurityLevel.S0 + kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, + securityLevel: distributedKVStore.SecurityLevel.S1 }; kvManager.getKVStore('storeId', options, function (err, store) { if (err) { - console.log("getKVStore err: " + JSON.stringify(err)); + console.error(`Failed to get KVStore: code is ${err.code},message is ${err.message}`); return; } - console.log("getKVStore success"); + console.log('Obtained KVStore successfully'); kvStore = store; }); } catch (e) { - console.log("An unexpected error occurred. Error: " + e); + console.error(`An unexpected error occurred.code is ${e.code},message is ${e.message}`); } ``` > **NOTE**
> > For data synchronization between networked devices, you are advised to open the distributed KV store during application startup to obtain the database handle. With this database handle (`kvStore` in this example), you can perform operations, such as inserting data into the KV store, without creating the KV store repeatedly during the lifecycle of the handle. - + 5. Subscribe to changes in the distributed data. The following is the sample code for subscribing to the data changes of a single KV store: ```js - kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_ALL, function (data) { - console.log("dataChange callback call data: " + JSON.stringify(data)); - }); + try{ + kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, function (data) { + console.log(`dataChange callback call data: ${data}`); + }); + }catch(e){ + console.error(`An unexpected error occured.code is ${e.code},message is ${e.message}`); + } ``` 6. Write data to the single KV store. @@ -151,15 +190,15 @@ The following uses a single KV store as an example to describe the development p const KEY_TEST_STRING_ELEMENT = 'key_test_string'; const VALUE_TEST_STRING_ELEMENT = 'value-test-string'; try { - kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, function (err, data) { + kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, function (err,data) { if (err != undefined) { - console.log("put err: " + JSON.stringify(err)); + console.error(`Failed to put.code is ${err.code},message is ${err.message}`); return; } - console.log("put success"); + console.log('Put data successfully'); }); - } catch (e) { - console.log("An unexpected error occurred. Error: " + e); + }catch (e) { + console.error(`An unexpected error occurred.code is ${e.code},message is ${e.message}`); } ``` @@ -174,18 +213,22 @@ The following uses a single KV store as an example to describe the development p const KEY_TEST_STRING_ELEMENT = 'key_test_string'; const VALUE_TEST_STRING_ELEMENT = 'value-test-string'; try { - kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, function (err, data) { + kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, function (err,data) { + if (err != undefined) { + console.error(`Failed to put.code is ${err.code},message is ${err.message}`); + return; + } + console.log('Put data successfully'); + kvStore.get(KEY_TEST_STRING_ELEMENT, function (err,data) { if (err != undefined) { - console.log("put err: " + JSON.stringify(err)); + console.error(`Failed to get data.code is ${err.code},message is ${err.message}`); return; } - console.log("put success"); - kvStore.get(KEY_TEST_STRING_ELEMENT, function (err, data) { - console.log("get success data: " + data); + console.log(`Obtained data successfully:${data}`); }); }); - } catch (e) { - console.log("An unexpected error occurred. Error: " + e); + }catch (e) { + console.error(`Failed to get.code is ${e.code},message is ${e.message}`); } ``` @@ -196,7 +239,7 @@ The following uses a single KV store as an example to describe the development p > **NOTE**
> > The APIs of the `deviceManager` module are system interfaces. - + The following is the example code for synchronizing data in a single KV store: ```js @@ -204,7 +247,7 @@ The following uses a single KV store as an example to describe the development p let devManager; // Create deviceManager. - deviceManager.createDeviceManager("bundleName", (err, value) => { + deviceManager.createDeviceManager('bundleName', (err, value) => { if (!err) { devManager = value; // deviceIds is obtained by deviceManager by calling getTrustedDeviceListSync(). @@ -217,9 +260,9 @@ The following uses a single KV store as an example to describe the development p } try{ // 1000 indicates that the maximum delay is 1000 ms. - kvStore.sync(deviceIds, distributedData.SyncMode.PUSH_ONLY, 1000); + kvStore.sync(deviceIds, distributedKVStore.SyncMode.PUSH_ONLY, 1000); } catch (e) { - console.log("An unexpected error occurred. Error: " + e); + console.error(`An unexpected error occurred. code is ${e.code},message is ${e.message}`); } } }); diff --git a/en/application-dev/database/database-mdds-overview.md b/en/application-dev/database/database-mdds-overview.md index 26efa7491805e871017db3593f5fa50d947717f5..cfe264a4f7eb06cd51cb834bc3e38ee27e649a14 100644 --- a/en/application-dev/database/database-mdds-overview.md +++ b/en/application-dev/database/database-mdds-overview.md @@ -1,105 +1,103 @@ # Distributed Data Service Overview -The distributed data service (DDS) implements distributed database collaboration across devices for applications. +The distributed data service (DDS) implements distributed database collaboration across devices for applications. Applications save data to distributed databases by calling the DDS APIs. The DDS isolates data of different applications based on a triplet of account, application, and database to ensure secure data access. The DDS synchronizes application data between trusted devices to provide users with consistent data access experience on different devices. You do not need to care about the implementation of the database locking mechanism. + ## Basic Concepts -- **KV data model** +### KV Data Model - The key-value \(KV\) data model allows data to be organized, indexed, and stored in key-value pairs. +The key-value (KV) data model allows data to be organized, indexed, and stored in KV pairs. - The KV data model is suitable for storing service data that is not related. It provides better read and write performance than the SQL database. The KV data model is widely used in distributed scenarios because it handles database version compatibility issues and data synchronization conflicts easily. The distributed database is based on the KV data model and provides KV-based access interfaces. +The KV data model is suitable for storing service data that is not related. It provides better read and write performance than the SQL database. The KV data model is widely used in distributed scenarios because it handles database version compatibility issues and data synchronization conflicts easily. The distributed database is based on the KV data model and provides KV-based access interfaces. -- **Distributed database transactions** +### Distributed Database Transaction - Distributed database transactions include local transactions \(same as the transactions of traditional databases\) and synchronization transactions. Synchronization transactions allow data to be synchronized between devices by local transaction. Synchronization of a local transaction modification either succeeds or fails on all the devices. +Distributed database transactions include local transactions (same as the transactions of traditional databases) and synchronization transactions. Synchronization transactions allow data to be synchronized between devices by local transaction. Synchronization of a local transaction modification either succeeds or fails on all the devices. -- **Distributed database consistency** +### Distributed Database Consistency - In a distributed scenario, cross-device collaboration demands consistent data between the devices in the same network. The data consistency can be classified into the following types: +In a distributed scenario, cross-device collaboration demands consistent data between the devices in the same network. The data consistency can be classified into the following types: - - **Strong consistency**: When data is inserted, deleted, or modified on a device, other devices in the same network will obtain the latest data immediately. - - **Weak consistency**: When data is added, deleted, or modified on a device, other devices in the same network may or may not obtain the latest data. The data on these devices may be inconsistent after a certain period of time. - - **Eventual consistency**: When data is added, deleted, or modified on a device, other devices in the same network may not obtain the latest data immediately. However, data on these devices will become consistent after a certain period of time. +- **Strong consistency**: When data is inserted, deleted, or modified on a device, other devices in the same network will obtain the latest data immediately. +- **Weak consistency**: When data is added, deleted, or modified on a device, other devices in the same network may or may not obtain the latest data. The data on these devices may be inconsistent after a certain period of time. +- **Eventual consistency**: When data is added, deleted, or modified on a device, other devices in the same network may not obtain the latest data immediately. However, data on these devices will become consistent after a certain period of time. - Strong consistency has high requirements on distributed data management and may be used in distributed server deployment. The DDS supports only the eventual consistency because mobile devices are not always online and the network has no center. +Strong consistency has high requirements on distributed data management and may be used in distributed server deployment. The DDS supports only the eventual consistency because mobile devices are not always online and the network has no center. -- **Distributed database synchronization** +### Distributed Database Synchronization - After discovering and authenticating a device, the underlying communication component notifies the upper-layer application \(including the DDS\) that the device goes online. The DDS then establishes an encrypted transmission channel to synchronize data between the two devices. +After discovering and authenticating a device, the underlying communication component notifies the upper-layer application (including the DDS) that the device goes online. The DDS then establishes an encrypted transmission channel to synchronize data between the two devices. - The DDS provides the following synchronization modes: +The DDS provides the following synchronization modes: - - **Manual synchronization**: Applications call **sync** to trigger a synchronization. The list of devices to be synchronized and the synchronization mode must be specified. The synchronization mode can be **PULL\_ONLY** \(pulling remote data to the local end\), **PUSH\_ONLY** \(pushing local data to the remote end\), or **PUSH\_PULL** \(pushing local data to the remote end and pulling remote data to the local end\). The internal interface supports condition-based synchronization. The data that meets the conditions can be synchronized to the remote end. - - **Automatic synchronization**: includes full synchronization and condition-based subscription synchronization. In full synchronization, the distributed database automatically pushes local data to the remote end and pulls remote data to the local end when a device goes online or application data is updated. Applications do not need to call **sync**. The internal interface supports condition-based subscription synchronization. The data that meets the subscription conditions on the remote end is automatically synchronized to the local end. +- **Manual synchronization**: Applications call **sync()** to trigger a synchronization. The list of devices to be synchronized and the synchronization mode must be specified. The synchronization mode can be **PULL_ONLY** (pulling remote data to the local end), **PUSH_ONLY** (pushing local data to the remote end), or **PUSH_PULL** (pushing local data to the remote end and pulling remote data to the local end). The internal interface supports condition-based synchronization. The data that meets the conditions can be synchronized to the remote end. +- **Automatic synchronization**: includes full synchronization and condition-based subscription synchronization. In full synchronization, the distributed database automatically pushes local data to the remote end and pulls remote data to the local end when a device goes online or application data is updated. Applications do not need to call **sync()**. The internal interface supports condition-based subscription synchronization. The data that meets the subscription conditions on the remote end is automatically synchronized to the local end. -- **Single KV store** +### Single KV Store - Data is saved locally in the unit of a single KV entry. Only one entry is saved for each key. Data can be modified only locally and synchronized to remote devices in sequence based on the update time. +Data is saved locally in the unit of a single KV entry. Only one entry is saved for each key. Data can be modified only locally and synchronized to remote devices in sequence based on the update time. -- **Device KV store** +### Device KV Store - The device KV store is based on the single KV store. The local device ID is added to the key when KV data is stored in the device KV store. Data can be isolated, managed, and queried by device. However, the data synchronized from remote devices cannot be modified locally. +The device KV store is based on the single KV store. The local device ID is added to the key when KV data is stored in the device KV store. Data can be isolated, managed, and queried by device. However, the data synchronized from remote devices cannot be modified locally. -- **Conflict resolution** +### Conflict Resolution - A data conflict occurs when multiple devices modify the same data and commit the modification to the database. The last write wins \(LWW\) is the default conflict resolution policy used for data conflicts. Based on the commit timestamps, the data with a later timestamp is used. Currently, customized conflict resolution policies are not supported. +A data conflict occurs when multiple devices modify the same data and commit the modification to the database. The last write wins (LWW) is the default conflict resolution policy used for data conflicts. Based on the commit timestamps, the data with a later timestamp is used. Currently, customized conflict resolution policies are not supported. -- **Schema-based database management and data query based on predicates** +### Schema-based Database Management and Predicate-based Data Query - A schema is specified when you create or open a single KV store. Based on the schema, the database detects the value format of key-value pairs and checks the value structure. Based on the fields in the values, the database implements index creation and predicate-based query. +A schema is specified when you create or open a single KV store. Based on the schema, the database detects the value format of KV pairs and checks the value structure. Based on the fields in the values, the database implements index creation and predicate-based query. -- **Distributed database backup** +### Distributed Database Backup - The DDS provides the database backup capability. You can set **backup** to **true** to enable daily backup. If a distributed database is damaged, the DDS deletes the database and restores the most recent data from the backup database. If no backup database is available, the DDS creates one. The DDS can also back up encrypted databases. +The DDS provides the database backup capability. You can set **backup** to **true** to enable daily backup. If a distributed database is damaged, the DDS deletes the database and restores the most recent data from the backup database. If no backup database is available, the DDS creates one. The DDS can also back up encrypted databases. ## Working Principles -The DDS supports distributed management of application database data in the OpenHarmony system. Data can be synchronized between multiple devices with the same account, delivering a consistent user experience across devices. The DDS consists of the following: +The DDS supports distributed management of application database data in the OpenHarmony system. Data can be synchronized between multiple devices with the same account, delivering a consistent user experience across devices. -- **APIs** +The DDS consists of the following: - The DDS provides APIs to create databases, access data, and subscribe to data. The APIs support the KV data model and common data types. They are highly compatible and easy to use, and can be released. +- **APIs**
The DDS provides APIs to create databases, access data, and subscribe to data. The APIs support the KV data model and common data types. They are highly compatible and easy to use, and can be released. -- **Service component** +- **Service component**
The service component implements management of metadata, permissions, encryption, backup and restore, and multiple users, and completes initialization of the storage component, synchronization component, and communication adaptation layer of the distributed database. - The service component implements management of metadata, permissions, encryption, backup and restore, and multiple users, and completes initialization of the storage component, synchronization component, and communication adaptation layer of the distributed database. +- **Storage component**
The storage component implements data access, data reduction, transactions, snapshots, database encryption, data combination, and conflict resolution. -- **Storage component** +- **Synchronization component**
The synchronization component interacts with the storage component and the communication adaptation layer to maintain data consistency between online devices. It synchronizes data generated on the local device to other devices and merges data from other devices into the local device. - The storage component implements data access, data reduction, transactions, snapshots, database encryption, data combination, and conflict resolution. +- **Communication adaptation layer**
The communication adaptation layer calls APIs of the underlying public communication layer to create and connect to communication channels, receive device online and offline messages, update metadata of the connected and disconnected devices, send device online and offline messages to the synchronization component. The synchronization component updates the list of connected devices, and calls the APIs of the communication adaption layer to encapsulate data and send the data to the connected devices. -- **Synchronization component** +Applications call the DDS APIs to create, access, and subscribe to distributed databases. The APIs store data to the storage component based on the capabilities provided by the service component. The storage component interacts with the synchronization component to synchronize data. The synchronization component uses the communication adaptation layer to synchronize data to remote devices, which update the data in the storage component and provide the data for applications through service APIs. - The synchronization component interacts with the storage component and the communication adaptation layer to maintain data consistency between online devices. It synchronizes data generated on the local device to other devices and merges data from other devices into the local device. -- **Communication adaptation layer** +**Figure 1** How DDS works - The communication adaptation layer calls APIs of the underlying public communication layer to create and connect to communication channels, receive device online and offline messages, update metadata of the connected and disconnected devices, send device online and offline messages to the synchronization component. The synchronization component updates the list of connected devices, and calls the APIs of the communication adaption layer to encapsulate data and send the data to the connected devices. +![](figures/en-us_image_0000001183386164.png) -Applications call the DDS APIs to create, access, and subscribe to distributed databases. The APIs store data to the storage component based on the capabilities provided by the service component. The storage component interacts with the synchronization component to synchronize data. The synchronization component uses the communication adaptation layer to synchronize data to remote devices, which update the data in the storage component and provide the data for applications through service APIs. -**Figure 1** How DDS works +## Constraints +- The DDS supports the KV data model only. It does not support foreign keys or triggers of the relational database. -![](figures/en-us_image_0000001183386164.png) +- The KV data model specifications supported by the DDS are as follows: -## Constraints + - For each record in a device KV store, the key must be less than or equal to 896 bytes and the value be less than 4 MB. + - For each record in a single KV store, the key must be less than or equal to 1 KB and the value be less than 4 MB. + - An application can open a maximum of 16 KV stores simultaneously. + +- The data that needs to be synchronized between devices should be stored in distributed databases rather than local databases. -- The DDS supports the KV data model only. It does not support foreign keys or triggers of the relational database. -- The KV data model specifications supported by the DDS are as follows: - - For each record in a device KV store, the key must be less than or equal to 896 bytes and the value be less than 4 MB. - - For each record in a single KV store, the key must be less than or equal to 1 KB and the value be less than 4 MB. - - An application can open a maximum of 16 KV stores simultaneously. +- The DDS does not support customized conflict resolution policies. -- The data that needs to be synchronized between devices should be stored in distributed databases rather than local databases. -- The DDS does not support customized conflict resolution policies. -- The maximum number of access requests to the KvStore API is 1000 per second and 10000 per minute. The maximum number of access requests to the KvManager API is 50 per second and 500 per minute. -- Blocking operations, such as modifying UI components, are not allowed in the distributed database event callback. +- The maximum number of access requests to the KvStore API is 1000 per second and 10000 per minute. The maximum number of access requests to the KvManager API is 50 per second and 500 per minute. +- Blocking operations, such as modifying UI components, are not allowed in the distributed database event callback. diff --git a/en/application-dev/database/database-preference-guidelines.md b/en/application-dev/database/database-preference-guidelines.md index 61aa2294c3f8ee077241e347e47e7780f50c4359..897be371287a22f8efe7a8571feec93458d1ba5f 100644 --- a/en/application-dev/database/database-preference-guidelines.md +++ b/en/application-dev/database/database-preference-guidelines.md @@ -28,26 +28,29 @@ Obtain a **Preferences** instance for data operations. A **Preferences** instanc | --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | ohos.data.preferences | getPreferences(context: Context, name: string): Promise\ | Obtains a **Preferences** instance.| -### Accessing Data +### Processing Data -Call the **put()** method to add or modify data in a **Preferences** instance. +Call **put()** to add or modify data in a **Preferences** instance. -Call the **get()** method to read data from a **Preferences** instance. +Call **get()** to read data from a **Preferences** instance. Call **getAll()** to obtain an **Object** instance that contains all KV pairs in a **Preferences** instance. -**Table 2** APIs for accessing **Preferences** data +Call **delete()** to delete the KV pair of the specified key from the **Preferences** instance. + +**Table 2** APIs for processing **Preferences** data | Class | API | Description | | ----------- | ---------------------------------------------------------- | ------------------------------------------------------------ | | Preferences | put(key: string, value: ValueType): Promise\ | Writes data to the **Preferences** instance. The value to write can be a number, a string, a Boolean value, or an array of numbers, strings, or Boolean values.| | Preferences | get(key: string, defValue: ValueType): Promise\ | Obtains data from the **Preferences** instance. The value to read can be a number, a string, a Boolean value, or an array of numbers, strings, or Boolean values.| -| Preferences | getAll(): Promise | Obtains an **Object** instance that contains all KV pairs in the **Preferences** instance. | +| Preferences | getAll(): Promise\ | Obtains an **Object** instance that contains all KV pairs in the **Preferences** instance. | +| Preferences | delete(key: string): Promise\ | Deletes the KV pair of the specified key from the **Preferences** instance. | ### Storing Data Persistently -Call the **flush()** method to write the cached data back to its text file for persistent storage. +Call **flush()** to write the cached data back to its text file for persistent storage. **Table 4** API for data persistence @@ -68,7 +71,7 @@ You can subscribe to data changes. When the value of the subscribed key is chang ### Deleting Data -Use the following APIs to delete a **Preferences** instance or data file. +You can use the following APIs to delete a **Preferences** instance or data file. **Table 6** APIs for deleting **Preferences** @@ -88,15 +91,22 @@ Use the following APIs to delete a **Preferences** instance or data file. 2. Obtain a **Preferences** instance. Read the specified file and load its data to the **Preferences** instance for data operations. - + FA model: ```js // Obtain the context. import featureAbility from '@ohos.ability.featureAbility' - var context = featureAbility.getContext() - + let context = featureAbility.getContext(); + + let preferences = null; let promise = data_preferences.getPreferences(context, 'mystore'); + + promise.then((pref) => { + preferences = pref; + }).catch((err) => { + console.info("Failed to get the preferences."); + }) ``` Stage model: @@ -104,53 +114,52 @@ Use the following APIs to delete a **Preferences** instance or data file. ```ts // Obtain the context. import Ability from '@ohos.application.Ability' - var context - class MainAbility extends Ability{ + let context = null; + let preferences = null; + export default class MainAbility extends Ability { onWindowStageCreate(windowStage){ - context = this.context + context = this.context; } } - + let promise = data_preferences.getPreferences(context, 'mystore'); + + promise.then((pref) => { + preferences = pref; + }).catch((err) => { + console.info("Failed to get the preferences."); + }) ``` 3. Write data. - Use the **preferences.put()** method to write data to the **Preferences** instance. + Use **preferences.put()** to write data to the **Preferences** instance. ```js - promise.then((preferences) => { - let putPromise = preferences.put('startup', 'auto'); - putPromise.then(() => { - console.info("Put the value of 'startup' successfully."); - }).catch((err) => { - console.info("Failed to put the value of 'startup'. Cause: " + err); - }) + let putPromise = preferences.put('startup', 'auto'); + putPromise.then(() => { + console.info("Put the value of 'startup' successfully."); }).catch((err) => { - console.info("Failed to get the preferences."); + console.info("Failed to put the value of 'startup'. Cause: " + err); }) ``` - + 4. Read data. - Use the **preferences.get()** method to read data. + Use **preferences.get()** to read data. ```js - promise.then((preferences) => { - let getPromise = preferences.get('startup', 'default'); - getPromise.then((value) => { + let getPromise = preferences.get('startup', 'default'); + getPromise.then((value) => { console.info("The value of 'startup' is " + value); - }).catch((err) => { - console.info("Failed to get the value of 'startup'. Cause: " + err); - }) }).catch((err) => { - console.info("Failed to get the preferences.") - }); + console.info("Failed to get the value of 'startup'. Cause: " + err); + }) ``` - + 5. Store data persistently. - Use the **flush()** method to flush data from the **Preferences** instance to its file. + Use **flush()** to flush data from the **Preferences** instance to its file. ```js preferences.flush(); @@ -161,16 +170,17 @@ Use the following APIs to delete a **Preferences** instance or data file. Specify an observer as the callback to subscribe to data changes for an application. When the value of the subscribed key is changed and saved by **flush()**, the observer callback will be invoked to return the new data. ```js - var observer = function (key) { + let observer = function (key) { console.info("The key" + key + " changed."); } preferences.on('change', observer); - preferences.put('startup', 'auto', function (err) { + // The data is changed from 'auto' to 'manual'. + preferences.put('startup', 'manual', function (err) { if (err) { console.info("Failed to put the value of 'startup'. Cause: " + err); return; } - console.info("Put the value of 'startup' successfully."); + console.info("Put the value of 'startup' successfully."); preferences.flush(function (err) { if (err) { console.info("Failed to flush data. Cause: " + err); @@ -183,7 +193,7 @@ Use the following APIs to delete a **Preferences** instance or data file. 7. Delete the specified file. - Use the **deletePreferences** method to delete the **Preferences** instance and its persistent file and backup and corrupted files. After the specified files are deleted, the application cannot use that instance to perform any data operation. Otherwise, data inconsistency will be caused. The deleted data and files cannot be restored. + Use **deletePreferences()** to delete the **Preferences** instance and its persistent file and backup and corrupted files. After the specified files are deleted, the application cannot use that instance to perform any data operation. Otherwise, data inconsistency will be caused. The deleted data and files cannot be restored. ```js let proDelete = data_preferences.deletePreferences(context, 'mystore'); diff --git a/en/application-dev/database/database-relational-guidelines.md b/en/application-dev/database/database-relational-guidelines.md index a4acbd9a7b47dca4332c7f6a881939b1928abd78..53e3ca5aeaa25ecea55f3e27272043e6b533e594 100644 --- a/en/application-dev/database/database-relational-guidelines.md +++ b/en/application-dev/database/database-relational-guidelines.md @@ -11,14 +11,14 @@ Most of the RDB store APIs are asynchronous interfaces, which can use a callback ### Creating or Deleting an RDB Store -The table below describes the APIs available for creating and deleting an RDB store. +The following table describes the APIs for creating and deleting an RDB store. **Table 1** APIs for creating and deleting an RDB store | API | Description | | ------------------------------------------------------------ | ------------------------------------------------------------ | -| getRdbStore(context: Context, config: StoreConfig, version: number): Promise<RdbStore> | Obtains an RDB store. This API uses a promise to return the result. You can set parameters for the RDB store based on service requirements and call APIs to perform data operations.
- **context**: context of the application or function.
- **config**: configuration of the RDB store.
- **version**: version of the RDB store.| -| deleteRdbStore(context: Context, name: string): Promise<void> | Deletes an RDB store. This API uses a promise to return the result.
- **context**: context of the application or function.
- **name**: name of the RDB store to delete.| +| getRdbStoreV9(context: Context, config: StoreConfigV9, version: number): Promise<RdbStoreV9> | Obtains an **RdbStoreV9** instance. This API uses a promise to return the result. You can set parameters for the RDB store based on service requirements and call APIs to perform data operations.
- **context**: context of the application or function.
- **config**: configuration of the RDB store.
- **version**: version of the RDB store. Currently, automatic RDB upgrades and downgrades performed based on **version** is not supported.| +| deleteRdbStoreV9(context: Context, name: string): Promise<void> | Deletes an RDB store. This API uses a promise to return the result.
- **context**: context of the application or function.
- **name**: name of the RDB store to delete.| ### Managing Data in an RDB Store @@ -31,31 +31,31 @@ The RDB provides APIs for inserting, deleting, updating, and querying data in th **Table 2** API for inserting data - | Class | API | Description | - | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | - | RdbStore | insert(table: string, values: ValuesBucket): Promise<number> | Inserts a row of data into a table. This API uses a promise to return the result.
If the operation is successful, the row ID will be returned; otherwise, **-1** will be returned.
- **table**: name of the target table.
- **values**: data to be inserted into the table.| + | Class | API | Description | + | ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | + | RdbStoreV9 | insert(table: string, values: ValuesBucket): Promise<number> | Inserts a row of data into a table. This API uses a promise to return the result.
If the operation is successful, the row ID will be returned; otherwise, **-1** will be returned.
- **table**: name of the target table.
- **values**: data to be inserted into the table.| - **Updating Data** - Call the **update()** method to pass new data and specify the update conditions by using **RdbPredicates**. If the data is updated, the number of rows of the updated data will be returned; otherwise, **0** will be returned. + Call **update()** to update data based on the passed data and the conditions specified by **RdbPredicatesV9**. If the data is updated, the number of rows of the updated data will be returned; otherwise, **0** will be returned. **Table 3** API for updating data - | Class | API | Description | - | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | - | RdbStore | update(values: ValuesBucket, predicates: RdbPredicates): Promise<number> | Updates data based on the specified **RdbPredicates** object. This API uses a promise to return the result.
the number of rows updated.
- **values**: data to update, which is stored in **ValuesBucket**.
- **predicates**: conditions for updating data.| + | Class | API | Description | + | ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | + | RdbStoreV9 | update(values: ValuesBucket, predicates: RdbPredicatesV9): Promise<number> | Updates data based on the specified **RdbPredicatesV9** object. This API uses a promise to return the number of rows updated.
- **values**: data to update, which is stored in **ValuesBucket**.
- **predicates**: conditions for updating data. | - **Deleting Data** - Call the **delete()** method to delete data meeting the conditions specified by **RdbPredicates**. If the data is deleted, the number of rows of the deleted data will be returned; otherwise, **0** will be returned. + Call **delete()** to delete the data that meets the conditions specified by **RdbPredicatesV9**. If the data is deleted, the number of rows of the deleted data will be returned; otherwise, **0** will be returned. **Table 4** API for deleting data - | Class | API | Description | - | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | - | RdbStore | delete(predicates: RdbPredicates): Promise<number> | Deletes data from the RDB store based on the specified **RdbPredicates** object. This API uses a promise to return
the number of rows updated.
- **predicates**: conditions for deleting data.| + | Class | API | Description | + | ---------- | ---------------------------------------------------------- | ------------------------------------------------------------ | + | RdbStoreV9 | delete(predicates: RdbPredicatesV9): Promise<number> | Deletes data from the RDB store based on the specified **RdbPredicatesV9** object. This API uses a promise to return the number of rows updated.
- **predicates**: conditions for deleting data. | - **Querying Data** @@ -67,62 +67,66 @@ The RDB provides APIs for inserting, deleting, updating, and querying data in th **Table 5** APIs for querying data - | Class | API | Description | - | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | - | RdbStore | query(predicates: RdbPredicates, columns?: Array<string>): Promise<ResultSet> | Queries data from the RDB store based on specified conditions. This API uses a promise to return the result.
- **predicates**: conditions for querying data.
- **columns**: columns to query. If this parameter is not specified, the query applies to all columns.| - | RdbStore | querySql(sql: string, bindArgs?: Array<ValueType>): Promise<ResultSet> | Queries data using the specified SQL statement. This API uses a promise to return the result.
- **sql**: SQL statement.
- **bindArgs**: arguments in the SQL statement.| - | RdbStore | remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array<string>): Promise<ResultSet> | Queries data from the database of a remote device based on specified conditions. This API uses a promise to return the result.
- **device**: network ID of the remote device.
- **table**: name of the table to be queried.
- **predicates**: **RdbPredicates** that specifies the query condition.
- **columns**: columns to query. If this parameter is not specified, the query applies to all columns.| +| Class | API | Description | +| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| RdbStoreV9 | query(predicates: RdbPredicatesV9, columns?: Array<string>): Promise<ResultSetV9> | Queries data from the RDB store based on specified conditions. This API uses a promise to return the result.
- **predicates**: conditions for querying data.
- **columns**: columns to query. If this parameter is not specified, the query applies to all columns.| +| RdbStoreV9 | querySql(sql: string, bindArgs?: Array<ValueType>): Promise<ResultSetV9> | Queries data using the specified SQL statement. This API uses a promise to return the result.
- **sql**: SQL statement.
- **bindArgs**: arguments in the SQL statement.| +| RdbStoreV9 | remoteQuery(device: string, table: string, predicates: RdbPredicatesV9, columns: Array<string>): Promise<ResultSetV9> | Queries data from the database of a remote device based on specified conditions. This API uses a promise to return the result.
- **device**: network ID of the remote device.
- **table**: name of the table to be queried.
- **predicates**: **RdbPredicatesV9** that specifies the query conditions.
- **columns**: columns to query. If this parameter is not specified, the query applies to all columns.| ### Using Predicates -The RDB provides **RdbPredicates** for you to set database operation conditions. +The **RDB** module provides **RdbPredicatesV9** for you to set database operation conditions. -The following lists common predicates. For more information about predicates, see [**RdbPredicates**](../reference/apis/js-apis-data-rdb.md#rdbpredicates). +The following table lists common predicates. For more information about predicates, see [**RdbPredicates**](../reference/apis/js-apis-data-rdb.md#rdbpredicates). **Table 6** APIs for using RDB store predicates -| Class | API | Description | -| ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbPredicates | equalTo(field: string, value: ValueType): RdbPredicates | Sets an **RdbPredicates** to match the field with data type **ValueType** and value equal to the specified value.
- **field**: column name in the database table.
- **value**: value to match the **RdbPredicates**.
- **RdbPredicates**: **RdbPredicates** object that matches the specified field.| -| RdbPredicates | notEqualTo(field: string, value: ValueType): RdbPredicates | Sets an **RdbPredicates** to match the field with data type **ValueType** and value not equal to the specified value.
- **field**: column name in the database table.
- **value**: value to match the **RdbPredicates**.
- **RdbPredicates**: **RdbPredicates** object that matches the specified field.| -| RdbPredicates | or(): RdbPredicates | Adds the OR condition to the **RdbPredicates**.
- **RdbPredicates**: **RdbPredicates** with the OR condition.| -| RdbPredicates | and(): RdbPredicates | Adds the AND condition to the **RdbPredicates**.
- **RdbPredicates**: **RdbPredicates** with the AND condition.| -| RdbPredicates | contains(field: string, value: string): RdbPredicates | Sets an **RdbPredicates** to match a string containing the specified value.
- **field**: column name in the database table.
- **value**: value to match the **RdbPredicates**.
- **RdbPredicates**: **RdbPredicates** object that matches the specified field.| +| Class | API | Description | +| --------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| RdbPredicatesV9 | equalTo(field: string, value: ValueType): RdbPredicatesV9 | Sets an **RdbPredicatesV9** to search for the data that is equal to the specified value.
- **field**: column name in the database table.
- **value**: value to match.
- **RdbPredicatesV9**: **RdbPredicatesV9** object created. | +| RdbPredicatesV9 | notEqualTo(field: string, value: ValueType): RdbPredicatesV9 | Sets an **RdbPredicatesV9** to search for the data that is not equal to the specified value.
- **field**: column name in the database table.
- **value**: value to match.
- **RdbPredicatesV9**: **RdbPredicatesV9** object created. | +| RdbPredicatesV9 | or(): RdbPredicatesV9 | Adds the OR condition to the **RdbPredicatesV9**.
- **RdbPredicatesV9**: **RdbPredicatesV9** with the OR condition. | +| RdbPredicatesV9 | and(): RdbPredicatesV9 | Adds the AND condition to the **RdbPredicatesV9**.
- **RdbPredicatesV9**: **RdbPredicatesV9** with the AND condition. | +| RdbPredicatesV9 | contains(field: string, value: string): RdbPredicatesV9 | Sets an **RdbPredicatesV9** to search for the data that contains the specified value.
- **field**: column name in the database table.
- **value**: value to match.
- **RdbPredicatesV9**: **RdbPredicatesV9** object created. | ### Using the Result Set -A result set can be regarded as a row of data in the queried results. It allows you to traverse and access the data you have queried. +You can use the APIs provided by **ResultSetV9** to traverse and access the data you have queried. A result set can be regarded as a row of data in the queried result. For details about how to use result set APIs, see [Result Set](../reference/apis/js-apis-data-resultset.md). -> **NOTICE**
+> **NOTICE** +> > After a result set is used, you must call the **close()** method to close it explicitly. **Table 7** APIs for using the result set -| Class | API | Description | -| --------- | ---------------------------------------------------- | ------------------------------------------ | -| ResultSet | goToFirstRow(): boolean | Moves to the first row of the result set. | -| ResultSet | getString(columnIndex: number): string | Obtains the value in the form of a string based on the specified column and current row. | -| ResultSet | getBlob(columnIndex: number): Uint8Array | Obtains the value in the form of a byte array based on the specified column and the current row.| -| ResultSet | getDouble(columnIndex: number): number | Obtains the value in the form of double based on the specified column and current row. | -| ResultSet | getLong(columnIndex: number): number | Obtains the value in the form of a long integer based on the specified column and current row. | -| ResultSet | close(): void | Closes the result set. | +| Class | API | Description | +| ----------- | ---------------------------------------- | ------------------------------------------ | +| ResultSetV9 | goToFirstRow(): boolean | Moves to the first row of the result set. | +| ResultSetV9 | getString(columnIndex: number): string | Obtains the value in the form of a string based on the specified column and current row. | +| ResultSetV9 | getBlob(columnIndex: number): Uint8Array | Obtains the value in the form of a byte array based on the specified column and the current row.| +| ResultSetV9 | getDouble(columnIndex: number): number | Obtains the value in the form of double based on the specified column and current row. | +| ResultSetV9 | getLong(columnIndex: number): number | Obtains the value in the form of a long integer based on the specified column and current row. | +| ResultSetV9 | close(): void | Closes the result set. | ### Setting Distributed Tables ->**CAUTION**
ohos.permission.DISTRIBUTED_DATASYNC is required for using the **setDistributedTables**, **obtainDistributedTableName**, **sync**, **on**, and **off** APIs of **RdbStore**. +> **NOTE** +> +> - The **ohos.permission.DISTRIBUTED_DATASYNC** permission is required for calling the **setDistributedTables**, **obtainDistributedTableName**, **sync**, **on** and **off** APIs of **RdbStore V9**. +> - The devices must be connected over network before the distributed tables are used. For details about the APIs and usage, see [Device Management](../reference/apis/js-apis-device-manager.md). **Setting Distributed Tables** **Table 8** API for setting distributed tables -| Class | API | Description | -| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbStore | setDistributedTables(tables: Array\): Promise\ | Sets distributed tables. This API uses a promise to return the result.
- **tables**: names of the distributed tables to set.| +| Class | API | Description | +| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| RdbStoreV9 | setDistributedTables(tables: Array\): Promise\ | Sets distributed tables. This API uses a promise to return the result.
- **tables**: names of the distributed tables to set.| **Obtaining the Distributed Table Name for a Remote Device** @@ -130,33 +134,33 @@ You can obtain the distributed table name for a remote device based on the local **Table 9** API for obtaining the distributed table name of a remote device -| Class | API | Description | -| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbStore | obtainDistributedTableName(device: string, table: string): Promise\ | Obtains the distributed table name for a remote device based on the local table name. The distributed table name is required when the RDB store of a remote device is queried. This API uses a promise to return the result.
- **device**: remote device.
- **table**: local table name.| +| Class | API | Description | +| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| RdbStoreV9 | obtainDistributedTableName(device: string, table: string): Promise\ | Obtains the distributed table name for a remote device based on the local table name. The distributed table name is required when the RDB store of a remote device is queried. This API uses a promise to return the result.
- **device**: remote device.
- **table**: local table name.| **Synchronizing Data Between Devices** **Table 10** API for synchronizing data between devices -| Class | API | Description | -| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbStore | sync(mode: SyncMode, predicates: RdbPredicates): Promise\> | Synchronizes data between devices. This API uses a promise to return the result.
- **mode**: synchronization mode. **SYNC_MODE_PUSH** means to push data from the local device to a remote device. **SYNC_MODE_PULL** means to pull data from a remote device to the local device.
- **predicates**: specifies the data and devices to synchronize.
- **string**: device ID.
- **number**: synchronization status of that device. The value **0** indicates a successful synchronization. Other values indicate a synchronization failure.| +| Class | API | Description | +| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| RdbStoreV9 | sync(mode: SyncMode, predicates: RdbPredicatesV9): Promise\> | Synchronizes data between devices. This API uses a promise to return the result.
- **mode**: synchronization mode. **SYNC_MODE_PUSH** means to push data from the local device to a remote device. **SYNC_MODE_PULL** means to pull data from a remote device to the local device.
- **predicates**: specifies the data and devices to synchronize.
- **string**: device ID.
- **number**: synchronization status of each device. The value **0** indicates a successful synchronization. Other values indicate a synchronization failure.| **Registering an RDB Store Observer** **Table 11** API for registering an observer -| Class | API | Description | -| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbStore | on(event: 'dataChange', type: SubscribeType, observer: Callback\>): void | Registers an observer for this RDB store to subscribe to distributed data changes. When data in the RDB store changes, a callback will be invoked to return the data changes.
- **type**: subscription type. **SUBSCRIBE_TYPE_REMOTE** means to subscribe to remote data changes.
- **observer**: observer that listens for data changes in the RDB store.| +| Class | API | Description | +| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| RdbStoreV9 | on(event: 'dataChange', type: SubscribeType, observer: Callback\>): void | Registers an observer for this RDB store to subscribe to distributed data changes. When data in the RDB store changes, a callback will be invoked to return the data changes.
- **type**: subscription type. **SUBSCRIBE_TYPE_REMOTE**: subscribes to remote data changes.
- **observer**: observer that listens for data changes in the RDB store.| **Unregistering an RDB Store Observer** **Table 12** API for unregistering an observer -| Class | API | Description | -| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbStore | off(event:'dataChange', type: SubscribeType, observer: Callback\>): void; | Unregisters the observer of the specified type from the RDB store. This API uses an asynchronous callback to return the result.
- **type**: subscription type. **SUBSCRIBE_TYPE_REMOTE** means to subscribe to remote data changes.
- **observer**: observer to unregister.| +| Class | API | Description | +| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| RdbStoreV9 | off(event:'dataChange', type: SubscribeType, observer: Callback\>): void; | Unregisters the observer of the specified type from the RDB store. This API uses an asynchronous callback to return the result.
- **type**: subscription type. **SUBSCRIBE_TYPE_REMOTE**: subscribes to remote data changes.
- **observer**: observer to unregister.| ### Backing Up and Restoring an RDB Store @@ -164,17 +168,17 @@ You can obtain the distributed table name for a remote device based on the local **Table 13** API for backing up an RDB store -| Class | API | Description | -| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbStore | backup(destName: string): Promise<void> | Backs up an RDB store. This API uses a promise to return the result.
- **destName**: name of the RDB backup file.| +| Class | API | Description | +| ---------- | --------------------------------------------- | ------------------------------------------------------------ | +| RdbStoreV9 | backup(destName: string): Promise<void> | Backs up an RDB store. This API uses a promise to return the result.
- **destName**: name of the RDB backup file.| **Restoring an RDB Store** **Table 14** API for restoring an RDB store -| Class | API | Description | -| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbStore | restore(srcName: string): Promise<void> | Restores an RDB store from a backup file. This API uses a promise to return the result.
- **srcName**: name of the backup file used to restore the RDB store.| +| Class | API | Description | +| ---------- | --------------------------------------------- | ------------------------------------------------------------ | +| RdbStoreV9 | restore(srcName: string): Promise<void> | Restores an RDB store from a backup file. This API uses a promise to return the result.
- **srcName**: name of the backup file used to restore the RDB store.| **Transaction** @@ -182,9 +186,9 @@ Table 15 Transaction APIs | Class | API | Description | | -------- | ----------------------- | --------------------------------- | -| RdbStore | beginTransaction(): void | Starts the transaction before executing SQL statements.| -| RdbStore | commit(): void | Commits the executed SQL statements. | -| RdbStore | rollBack(): void | Rolls back the SQL statements that have been executed. | +| RdbStoreV9 | beginTransaction(): void | Starts the transaction before executing SQL statements.| +| RdbStoreV9 | commit(): void | Commits the executed SQL statements. | +| RdbStoreV9 | rollBack(): void | Rolls back the SQL statements that have been executed. | ## How to Develop @@ -196,18 +200,44 @@ Table 15 Transaction APIs (3) Create an RDB store. - The sample code is as follows: + FA model: ```js - import data_rdb from '@ohos.data.rdb' - - const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "name TEXT NOT NULL, " + "age INTEGER, " + "salary REAL, " + "blobType BLOB)"; - const STORE_CONFIG = { name: "rdbstore.db" } - data_rdb.getRdbStore(this.context, STORE_CONFIG, 1, function (err, rdbStore) { - rdbStore.executeSql(CREATE_TABLE_TEST) + import data_rdb from '@ohos.data.rdb' + // Obtain the context. + import featureAbility from '@ohos.ability.featureAbility' + let context = featureAbility.getContext() + + const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "name TEXT NOT NULL, " + "age INTEGER, " + "salary REAL, " + "blobType BLOB)"; + + const STORE_CONFIGV9 = { name: "RdbTest.db", + securityLevel: data_rdb.SecurityLevel.S1} + data_rdb.getRdbStoreV9(context, STORE_CONFIGV9, 1, function (err, rdbStoreV9) { + rdbStoreV9.executeSql(CREATE_TABLE_TEST) console.info('create table done.') - }) + }) ``` + Stage model: + ```ts + import data_rdb from '@ohos.data.rdb' + // Obtain the context. + import Ability from '@ohos.application.Ability' + let context = null + class MainAbility extends Ability { + onWindowStageCreate(windowStage) { + context = this.context + } + } + + const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "name TEXT NOT NULL, " + "age INTEGER, " + "salary REAL, " + "blobType BLOB)"; + + const STORE_CONFIGV9 = { name: "rdbstore.db", + securityLevel: data_rdb.SecurityLevel.S1} + data_rdb.getRdbStoreV9(context, STORE_CONFIGV9, 1, function (err, rdbStoreV9) { + rdbStoreV9.executeSql(CREATE_TABLE_TEST) + console.info('create table done.') + }) + ``` 2. Insert data. @@ -220,12 +250,12 @@ Table 15 Transaction APIs ```js var u8 = new Uint8Array([1, 2, 3]) const valueBucket = { "name": "Tom", "age": 18, "salary": 100.5, "blobType": u8 } - let insertPromise = rdbStore.insert("test", valueBucket) + let insertPromise = rdbStoreV9.insert("test", valueBucket) ``` 3. Query data. - (1) Create an **RdbPredicates** object to specify query conditions. + (1) Create an **RdbPredicatesV9** object to specify query conditions. (2) Call the **query()** API to query data. @@ -234,17 +264,17 @@ Table 15 Transaction APIs The sample code is as follows: ```js - let predicates = new data_rdb.RdbPredicates("test"); - predicates.equalTo("name", "Tom") - let promisequery = rdbStore.query(predicates) - promisequery.then((resultSet) => { - resultSet.goToFirstRow() - const id = resultSet.getLong(resultSet.getColumnIndex("id")) - const name = resultSet.getString(resultSet.getColumnIndex("name")) - const age = resultSet.getLong(resultSet.getColumnIndex("age")) - const salary = resultSet.getDouble(resultSet.getColumnIndex("salary")) - const blobType = resultSet.getBlob(resultSet.getColumnIndex("blobType")) - resultSet.close() + let predicatesV9 = new data_rdb.RdbPredicatesV9("test"); + predicatesV9.equalTo("name", "Tom") + let promisequery = rdbStoreV9.query(predicatesV9) + promisequery.then((resultSetV9) => { + resultSetV9.goToFirstRow() + const id = resultSetV9.getLong(resultSetV9.getColumnIndex("id")) + const name = resultSetV9.getString(resultSetV9.getColumnIndex("name")) + const age = resultSetV9.getLong(resultSetV9.getColumnIndex("age")) + const salary = resultSetV9.getDouble(resultSetV9.getColumnIndex("salary")) + const blobType = resultSetV9.getBlob(resultSetV9.getColumnIndex("blobType")) + resultSetV9.close() }) ``` @@ -272,7 +302,7 @@ Table 15 Transaction APIs context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) { console.info(`result.requestCode=${result.requestCode}`) }) - let promise = rdbStore.setDistributedTables(["test"]) + let promise = rdbStoreV9.setDistributedTables(["test"]) promise.then(() => { console.info("setDistributedTables success.") }).catch((err) => { @@ -282,7 +312,7 @@ Table 15 Transaction APIs 5. Synchronize data across devices. - (1) Construct an **RdbPredicates** object to specify remote devices within the network to be synchronized. + (1) Construct an **RdbPredicatesV9** object to specify remote devices within the network to be synchronized. (2) Call **rdbStore.sync()** to synchronize data. @@ -291,9 +321,9 @@ Table 15 Transaction APIs The sample code is as follows: ```js - let predicate = new data_rdb.RdbPredicates('test') - predicate.inDevices(['12345678abcde']) - let promise = rdbStore.sync(data_rdb.SyncMode.SYNC_MODE_PUSH, predicate) + let predicateV9 = new data_rdb.RdbPredicatesV9('test') + predicateV9.inDevices(['12345678abcde']) + let promise = rdbStoreV9.sync(data_rdb.SyncMode.SYNC_MODE_PUSH, predicateV9) promise.then((result) => { console.log('sync done.') for (let i = 0; i < result.length; i++) { @@ -318,9 +348,9 @@ Table 15 Transaction APIs console.log('device=' + device[i] + 'data changed') } } - + try { - rdbStore.on('dataChange', data_rdb.SubscribeType.SUBSCRIBE_TYPE_REMOTE, storeObserver) + rdbStoreV9.on('dataChange', data_rdb.SubscribeType.SUBSCRIBE_TYPE_REMOTE, storeObserver) } catch (err) { console.log('register observer failed') } @@ -335,8 +365,8 @@ Table 15 Transaction APIs The sample code is as follows: ```js - let tableName = rdbStore.obtainDistributedTableName(deviceId, "test"); - let resultSet = rdbStore.querySql("SELECT * FROM " + tableName) + let tableName = rdbStoreV9.obtainDistributedTableName(deviceId, "test"); + let resultSetV9 = rdbStoreV9.querySql("SELECT * FROM " + tableName) ``` 8. Query data of a remote device. @@ -349,17 +379,17 @@ Table 15 Transaction APIs The sample code is as follows: ```js - let rdbPredicate = new data_rdb.RdbPredicates('employee') - predicates.greaterThan("id", 0) - let promiseQuery = rdbStore.remoteQuery('12345678abcde', 'employee', rdbPredicate) - promiseQuery.then((resultSet) => { - while (resultSet.goToNextRow()) { - let idx = resultSet.getLong(0); - let name = resultSet.getString(1); - let age = resultSet.getLong(2); + let rdbPredicateV9 = new data_rdb.RdbPredicatesV9('employee') + predicatesV9.greaterThan("id", 0) + let promiseQuery = rdbStoreV9.remoteQuery('12345678abcde', 'employee', rdbPredicateV9) + promiseQuery.then((resultSetV9) => { + while (resultSetV9.goToNextRow()) { + let idx = resultSetV9.getLong(0); + let name = resultSetV9.getString(1); + let age = resultSetV9.getLong(2); console.info(idx + " " + name + " " + age); } - resultSet.close(); + resultSetV9.close(); }).catch((err) => { console.info("failed to remoteQuery, err: " + err) }) @@ -372,7 +402,7 @@ Table 15 Transaction APIs The sample code is as follows: ```js - let promiseBackup = rdbStore.backup("dbBackup.db") + let promiseBackup = rdbStoreV9.backup("dbBackup.db") promiseBackup.then(() => { console.info('Backup success.') }).catch((err) => { @@ -384,7 +414,7 @@ Table 15 Transaction APIs The sample code is as follows: ```js - let promiseRestore = rdbStore.restore("dbBackup.db") + let promiseRestore = rdbStoreV9.restore("dbBackup.db") promiseRestore.then(() => { console.info('Restore success.') }).catch((err) => { diff --git a/en/application-dev/device-usage-statistics/Readme-EN.md b/en/application-dev/device-usage-statistics/Readme-EN.md index 75cfad35e1f36bfe07f0cb408c936f87e0ee520a..ccdf5a72d692b5e5e62a906819de1d6681ccfacf 100644 --- a/en/application-dev/device-usage-statistics/Readme-EN.md +++ b/en/application-dev/device-usage-statistics/Readme-EN.md @@ -1,4 +1,5 @@ # Device Usage Statistics - [Device Usage Statistics Overview](device-usage-statistics-overview.md) -- [Device Usage Statistics Development](device-usage-statistics-dev-guide.md) +- [Device Usage Statistics Development](device-usage-statistics-use-guide.md) + diff --git a/en/application-dev/device-usage-statistics/device-usage-statistics-dev-guide.md b/en/application-dev/device-usage-statistics/device-usage-statistics-dev-guide.md deleted file mode 100644 index f18f59468d0650400adfb50b87645c763a740b9c..0000000000000000000000000000000000000000 --- a/en/application-dev/device-usage-statistics/device-usage-statistics-dev-guide.md +++ /dev/null @@ -1,439 +0,0 @@ -# Device Usage Statistics Development - -## When to Use - -With device usage statistics APIs, you can have a better understanding of the application, notification, and system usage. For example, in application usage statistics, you can query the application usage, event log, and bundle group. -The application records (usage history statistics and event records) cached by components are updated to the database for persistent storage within 30 minutes after an event is reported. - -## Available APIs -Import the **stats** package to implement registration: -```js -import stats from '@ohos.bundleState'; -``` - -**Table 1** Major APIs for device usage statistics - -| API| Description| -| -------- | -------- | -| function queryBundleActiveStates(begin: number, end: number, callback: AsyncCallback<Array<BundleActiveState>>): void | Queries events of all applications based on the specified start time and end time.| -| function queryBundleStateInfos(begin: number, end: number, callback: AsyncCallback<BundleActiveInfoResponse>): void | Queries the application usage duration statistics based on the specified start time and end time.| -| function queryCurrentBundleActiveStates(begin: number, end: number, callback: AsyncCallback<Array<BundleActiveState>>): void | Queries events of this application based on the specified start time and end time.| -| function queryBundleStateInfoByInterval(byInterval: IntervalType, begin: number, end: number, callback: AsyncCallback<Array<BundleStateInfo>>): void | Queries the application usage duration statistics in the specified time frame at the specified interval (daily, weekly, monthly, or annually).| -| function queryAppUsagePriorityGroup(callback: AsyncCallback<number>): void | Queries the priority group of this application. This API uses an asynchronous callback to return the result.| -| function queryAppUsagePriorityGroup(): Promise<number>; | Queries the priority group of this application. This API uses a promise to return the result.| -| function isIdleState(bundleName: string, callback: AsyncCallback<boolean>): void | Checks whether the application specified by **bundleName** is in the idle state. | -| function getRecentlyUsedModules(callback: AsyncCallback<BundleActiveModuleInfo>): void | Obtains the number of FA usage records specified by **1000**.| -| function getRecentlyUsedModules(maxNum: number, callback: AsyncCallback<BundleActiveModuleInfo>): void | Obtains the number of FA usage records specified by **maxNum**.| -| function queryAppNotificationNumber(begin: number, end: number, callback: AsyncCallback<Array<BundleActiveEventState>>): void | Queries the number of notifications from all applications based on the specified start time and end time.| -| function queryBundleActiveEventStates(begin: number, end: number, callback: AsyncCallback<Array<BundleActiveEventState>>): void | Queries statistics about system events (hibernation, wakeup, unlocking, and screen locking) that occur between the specified start time and end time.| -| function queryAppUsagePriorityGroup(bundleName : string, callback: AsyncCallback<number>): void | Queries the priority group of the application specified by **bundleName**. This API uses an asynchronous callback to return the result.| -| function queryAppUsagePriorityGroup(bundleName? : string): Promise<number>; | Queries the priority group of the application specified by **bundleName**. If **bundleName** is not specified, the priority group of the current application is queried. This API uses a promise to return the result.| -| function setBundleGroup(bundleName : string, newGroup: GroupType, callback: AsyncCallback>boolean>): void | Sets the group for the application specified by **bundleName**. This API uses an asynchronous callback to return the result.| -| function setBundleGroup(bundleName : string, newGroup : GroupType): Promise>boolean>; | Sets the group for the application specified by **bundleName**. This API uses a promise to return the result.| -| function registerGroupCallBack(groupCallback: Callback>BundleActiveGroupCallbackInfo>, callback: AsyncCallback>boolean>): void | Registers a callback for application group changes. When an application group of the user changes, the change is returned to all applications that have registered the callback. This API uses an asynchronous callback to return the result.| -| function registerGroupCallBack(groupCallback: Callback>BundleActiveGroupCallbackInfo>): Promise>boolean>; | Registers a callback for application group changes. When an application group of the user changes, the change is returned to all applications that have registered the callback. This API uses a promise to return the result.| -| function unRegisterGroupCallBack(callback: AsyncCallback>boolean>): void | Deregisters the callback for application group changes. This API uses an asynchronous callback to return the result.| -| function unRegisterGroupCallBack(): Promise>boolean>; | Deregisters the callback for application group changes. This API uses a promise to return the result.| - -## How to Develop - -1. Configure the device usage statistics permission in the **config.json** file. - - ```json - "module": { - "package": "com.example.deviceUsageStatistics", - ..., - "reqPermissions": [ - { - "name": "ohos.permission.BUNDLE_ACTIVE_INFO" - } - ] - } - ``` - -2. Query events of all applications based on the specified start time and end time. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured in the **config.json** file. - - ```js - import stats from '@ohos.bundleState' - - // Promise mode - stats.queryBundleActiveStates(0, 20000000000000).then(res => { - console.log('BUNDLE_ACTIVE queryBundleActiveStates promise success.'); - for (let i = 0; i < res.length; i++) { - console.log('BUNDLE_ACTIVE queryBundleActiveStates promise number : ' + (i + 1)); - console.log('BUNDLE_ACTIVE queryBundleActiveStates promise result ' + JSON.stringify(res[i])); - } - }).catch(err => { - console.log('BUNDLE_ACTIVE queryBundleActiveStates promise failed, because: ' + err.code); - }); - - // Asynchronous callback mode - stats.queryBundleActiveStates(0, 20000000000000, (err, res) => { - if (err) { - console.log('BUNDLE_ACTIVE queryBundleActiveStates callback failed, because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE queryBundleActiveStates callback success.'); - for (let i = 0; i < res.length; i++) { - console.log('BUNDLE_ACTIVE queryBundleActiveStates callback number : ' + (i + 1)); - console.log('BUNDLE_ACTIVE queryBundleActiveStates callback result ' + JSON.stringify(res[i])); - } - } - }); - ``` - -3. Query the application usage duration statistics based on the specified start time and end time. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured in the **config.json** file. - - ```js - import stats from '@ohos.bundleState' - - // Promise mode - stats.queryBundleStateInfos(0, 20000000000000).then(res => { - console.log('BUNDLE_ACTIVE queryBundleStateInfos promise success.'); - let i = 1; - for (let key in res){ - console.log('BUNDLE_ACTIVE queryBundleStateInfos promise number : ' + i); - console.log('BUNDLE_ACTIVE queryBundleStateInfos promise result ' + JSON.stringify(res[key])); - i++; - } - }).catch(err => { - console.log('BUNDLE_ACTIVE queryBundleStateInfos promise failed, because: ' + err.code); - }); - - // Asynchronous callback mode - stats.queryBundleStateInfos(0, 20000000000000, (err, res) => { - if (err) { - console.log('BUNDLE_ACTIVE queryBundleStateInfos callback failed, because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE queryBundleStateInfos callback success.'); - let i = 1; - for(let key in res){ - console.log('BUNDLE_ACTIVE queryBundleStateInfos callback number : ' + i); - console.log('BUNDLE_ACTIVE queryBundleStateInfos callback result ' + JSON.stringify(res[key])); - i++; - } - } - }); - ``` - -4. Query events of this application based on the specified start time and end time. This requires no permission to be configured in the **config.json** file. - - ```js - import stats from '@ohos.bundleState' - - // Promise mode - stats.queryCurrentBundleActiveStates(0, 20000000000000).then(res => { - console.log('BUNDLE_ACTIVE queryCurrentBundleActiveStates promise success.'); - for (let i = 0; i < res.length; i++) { - console.log('BUNDLE_ACTIVE queryCurrentBundleActiveStates promise number : ' + (i + 1)); - console.log('BUNDLE_ACTIVE queryCurrentBundleActiveStates promise result ' + JSON.stringify(res[i])); - } - }).catch(err => { - console.log('BUNDLE_ACTIVE queryCurrentBundleActiveStates promise failed, because: ' + err.code); - }); - - // Asynchronous callback mode - stats.queryCurrentBundleActiveStates(0, 20000000000000, (err, res) => { - if (err) { - console.log('BUNDLE_ACTIVE queryCurrentBundleActiveStates callback failed, because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE queryCurrentBundleActiveStates callback success.'); - for (let i = 0; i < res.length; i++) { - console.log('BUNDLE_ACTIVE queryCurrentBundleActiveStates callback number : ' + (i + 1)); - console.log('BUNDLE_ACTIVE queryCurrentBundleActiveStates callback result ' + JSON.stringify(res[i])); - } - } - }); - ``` - -5. Query the application usage duration statistics in the specified time frame at the specified interval (daily, weekly, monthly, or annually). This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured in the **config.json** file. - - ```js - import stats from '@ohos.bundleState' - - // Promise mode - stats.queryBundleStateInfoByInterval(0, 0, 20000000000000).then(res => { - console.log('BUNDLE_ACTIVE queryBundleStateInfoByInterval promise success.'); - for (let i = 0; i < res.length; i++) { - console.log('BUNDLE_ACTIVE queryBundleStateInfoByInterval promise number : ' + (i + 1)); - console.log('BUNDLE_ACTIVE queryBundleStateInfoByInterval promise result ' + JSON.stringify(res[i])); - } - }).catch(err => { - console.log('BUNDLE_ACTIVE queryBundleStateInfoByInterval promise failed, because: ' + err.code); - }); - - // Asynchronous callback mode - stats.queryBundleStateInfoByInterval(0, 0, 20000000000000, (err, res) => { - if (err) { - console.log('BUNDLE_ACTIVE queryBundleStateInfoByInterval callback failed, because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE queryBundleStateInfoByInterval callback success.'); - for (let i = 0; i < res.length; i++) { - console.log('BUNDLE_ACTIVE queryBundleStateInfoByInterval callback number : ' + (i + 1)); - console.log('BUNDLE_ACTIVE queryBundleStateInfoByInterval callback result ' + JSON.stringify(res[i])); - } - } - }); - ``` - -6. Query the priority group of the current application. This requires no permission to be configured in the **config.json** file. - - ```js - import stats from '@ohos.bundleState' - - // Promise mode - stats.queryAppUsagePriorityGroup().then(res => { - console.log('BUNDLE_ACTIVE queryAppUsagePriorityGroup promise succeeded. result: ' + JSON.stringify(res)); - }).catch(err => { - console.log('BUNDLE_ACTIVE queryAppUsagePriorityGroup promise failed. because: ' + err.code); - }); - - // Callback mode - stats.queryAppUsagePriorityGroup((err, res) => { - if (err) { - console.log('BUNDLE_ACTIVE queryAppUsagePriorityGroup callback failed. because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE queryAppUsagePriorityGroup callback succeeded. result: ' + JSON.stringify(res)); - } - }); - ``` - -7. Check whether the application specified by **bundleName** is in the idle state. This requires no permission to be configured in the **config.json** file. A third-party application can only check the idle status of itself. - - ```js - import stats from '@ohos.bundleState' - - // Promise mode - stats.isIdleState("com.ohos.camera").then(res => { - console.log('BUNDLE_ACTIVE isIdleState promise succeeded, result: ' + JSON.stringify(res)); - }).catch(err => { - console.log('BUNDLE_ACTIVE isIdleState promise failed, because: ' + err.code); - }); - - // Asynchronous callback mode - stats.isIdleState("com.ohos.camera", (err, res) => { - if (err) { - console.log('BUNDLE_ACTIVE isIdleState callback failed, because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE isIdleState callback succeeded, result: ' + JSON.stringify(res)); - } - }); - ``` - -8. Obtain the number of FA usage records specified by **maxNum**. If **maxNum** is not specified, the default value **1000** is used. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured in the **config.json** file. - - ```js - import stats from '@ohos.bundleState' - - // Promise mode - stats.getRecentlyUsedModules(1000).then(res => { - console.log('BUNDLE_ACTIVE getRecentlyUsedModules promise succeeded'); - for (let i = 0; i < res.length; i++) { - console.log('BUNDLE_ACTIVE getRecentlyUsedModules promise number : ' + (i + 1)); - console.log('BUNDLE_ACTIVE getRecentlyUsedModules promise result ' + JSON.stringify(res[i])); - } - }).catch(err=> { - console.log('BUNDLE_ACTIVE getRecentlyUsedModules promise failed, because: ' + err.code); - }); - - // Promise mode when maxNum is not specified - stats.getRecentlyUsedModules().then(res => { - console.log('BUNDLE_ACTIVE getRecentlyUsedModules promise succeeded'); - for (let i = 0; i < res.length; i++) { - console.log('BUNDLE_ACTIVE getRecentlyUsedModules promise number : ' + (i + 1)); - console.log('BUNDLE_ACTIVE getRecentlyUsedModules promise result ' + JSON.stringify(res[i])); - } - }).catch( err=> { - console.log('BUNDLE_ACTIVE getRecentlyUsedModules promise failed, because: ' + err.code); - }); - - // Asynchronous callback mode - stats.getRecentlyUsedModules(1000, (err, res) => { - if(err) { - console.log('BUNDLE_ACTIVE getRecentlyUsedModules callback failed, because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE getRecentlyUsedModules callback succeeded.'); - for (let i = 0; i < res.length; i++) { - console.log('BUNDLE_ACTIVE getRecentlyUsedModules callback number : ' + (i + 1)); - console.log('BUNDLE_ACTIVE getRecentlyUsedModules callback result ' + JSON.stringify(res[i])); - } - } - }); - - // Asynchronous callback mode when maxNum is not specified - stats.getRecentlyUsedModules((err, res) => { - if (err) { - console.log('BUNDLE_ACTIVE getRecentlyUsedModules callback failed, because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE getRecentlyUsedModules callback succeeded.'); - for (let i = 0; i < res.length; i++) { - console.log('BUNDLE_ACTIVE getRecentlyUsedModules callback number : ' + (i + 1)); - console.log('BUNDLE_ACTIVE getRecentlyUsedModules callback result ' + JSON.stringify(res[i])); - } - } - }); - ``` - -9. Query the number of notifications from all applications based on the specified start time and end time. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured in the **config.json** file. - - ```js - import stats from '@ohos.bundleState' - - // Promise mode - stats.queryAppNotificationNumber(0, 20000000000000).then(res => { - console.log('BUNDLE_ACTIVE queryAppNotificationNumber promise success.'); - console.log('BUNDLE_ACTIVE queryAppNotificationNumber promise result ' + JSON.stringify(res)); - }).catch(err => { - console.log('BUNDLE_ACTIVE queryAppNotificationNumber promise failed, because: ' + err.code); - }); - - // Asynchronous callback mode - stats.queryAppNotificationNumber(0, 20000000000000, (err, res) => { - if (err) { - console.log('BUNDLE_ACTIVE queryAppNotificationNumber callback failed, because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE queryAppNotificationNumber callback success.'); - console.log('BUNDLE_ACTIVE queryAppNotificationNumber callback result ' + JSON.stringify(res)); - } - }); - ``` - -10. Query statistics about system events (hibernation, wakeup, unlocking, and screen locking) that occur between the specified start time and end time. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured in the **config.json** file. - - ```js - import stats from '@ohos.bundleState' - - // Promise mode - stats.queryBundleActiveEventStates(0, 20000000000000).then(res => { - console.log('BUNDLE_ACTIVE queryBundleActiveEventStates promise success.'); - console.log('BUNDLE_ACTIVE queryBundleActiveEventStates promise result ' + JSON.stringify(res)); - }).catch(err => { - console.log('BUNDLE_ACTIVE queryBundleActiveEventStates promise failed, because: ' + err.code); - }); - - // Asynchronous callback mode - stats.queryBundleActiveEventStates(0, 20000000000000, (err, res) => { - if (err) { - console.log('BUNDLE_ACTIVE queryBundleActiveEventStates callback failed, because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE queryBundleActiveEventStates callback success.'); - console.log('BUNDLE_ACTIVE queryBundleActiveEventStates callback result ' + JSON.stringify(res)); - } - }); - ``` - -11. Query the priority group of the current application. This requires no permission to be configured in the **config.json** file. Query the priority group of a specified application. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured in the **config.json** file. - - ```js - import stats from '@ohos.bundleState' - - // Promise mode without parameters - stats.queryAppUsagePriorityGroup().then(res => { - console.log('BUNDLE_ACTIVE queryAppUsagePriorityGroup promise succeeded. result: ' + JSON.stringify(res)); - }).catch(err => { - console.log('BUNDLE_ACTIVE queryAppUsagePriorityGroup promise failed. because: ' + err.code); - }); - - // Asynchronous callback mode without parameters - stats.queryAppUsagePriorityGroup((err, res) => { - if (err) { - console.log('BUNDLE_ACTIVE queryAppUsagePriorityGroup callback failed. because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE queryAppUsagePriorityGroup callback succeeded. result: ' + JSON.stringify(res)); - } - }); - - // Promise mode with parameters - stats.queryAppUsagePriorityGroup(this.bundleName).then(res => { - console.log('BUNDLE_ACTIVE QueryPackageGroup promise succeeded. result: ' + JSON.stringify(res)); - }).catch(err => { - console.log('BUNDLE_ACTIVE QueryPackageGroup promise failed. because: ' + err.code); - }); - - // Asynchronous callback mode with parameters - stats.queryAppUsagePriorityGroup(this.bundleName, (err, res) => { - if (err) { - console.log('BUNDLE_ACTIVE QueryPackageGroup callback failed. because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE QueryPackageGroup callback succeeded. result: ' + JSON.stringify(res)); - } - }); - ``` - -11. Set the group for the application specified by **bundleName**. - - ```javascript - import stats from '@ohos.bundleState' - - // Promise mode - stats.setBundleGroup(this.bundleName, this.newGroup).then(() => { - console.log('BUNDLE_ACTIVE SetBundleGroup promise succeeded.'); - }).catch( err => { - console.log('BUNDLE_ACTIVE SetBundleGroup promise failed. because: ' + err.code); - }); - // Asynchronous callback mode - stats.setBundleGroup(this.bundleName, this.newGroup, (err) => { - if (err) { - console.log('BUNDLE_ACTIVE SetBundleGroup callback failed. because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE SetBundleGroup callback succeeded.'); - } - }); - ``` - -12. Register a callback for application group changes. When an application group of the user changes, the change is returned to all applications that have registered the callback. - - ```javascript - import stats from '@ohos.bundleState' - - // Promise mode - let onBundleGroupChanged = (err,res) => { - console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack callback success.'); - console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack result oldGroup is : ' + res.oldGroup); - console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack result newGroup is : ' + res.newGroup); - console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack result changeReason is : ' + res.newGroup); - console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack result userId is : ' + res.userId); - console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack result bundleName is : ' + res.bundleName); - }; - stats.registerGroupCallBack(onBundleGroupChanged).then(() => { - console.log('BUNDLE_ACTIVE RegisterGroupCallBack promise succeeded.'); - }).catch(err => { - console.log('BUNDLE_ACTIVE RegisterGroupCallBack promise failed. because: ' + err.code); - }); - // Asynchronous callback mode - let onBundleGroupChanged = (err,res) => { - console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack callback success.'); - console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack result's oldGroup is : ' + res.oldGroup); - console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack result's newGroup is : ' + res.newGroup); - console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack result's changeReason is : ' + res.newGroup); - console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack result's userId is : ' + res.userId); - console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack result's bundleName is : ' + res.bundleName); - }; - stats.registerGroupCallBack(onBundleGroupChanged, (err) => { - if (err) { - console.log('BUNDLE_ACTIVE RegisterGroupCallBack callback failed, because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE RegisterGroupCallBack callback success.'); - } - }); - ``` - -13. Deregister the callback for application group changes. - - ```javascript - import stats from '@ohos.bundleState' - - // Promise mode - stats.unRegisterGroupCallBack().then(() => { - console.log('BUNDLE_ACTIVE UnRegisterGroupCallBack promise succeeded.'); - }).catch(err => { - console.log('BUNDLE_ACTIVE UnRegisterGroupCallBack promise failed. because: ' + err.code); - }); - // Asynchronous callback mode - stats.unRegisterGroupCallBack((err) => { - if (err) { - console.log('BUNDLE_ACTIVE UnRegisterGroupCallBack callback failed, because: ' + err.code); - } else { - console.log('BUNDLE_ACTIVE UnRegisterGroupCallBack callback success.'); - } - }); - ``` diff --git a/en/application-dev/device-usage-statistics/device-usage-statistics-use-guide.md b/en/application-dev/device-usage-statistics/device-usage-statistics-use-guide.md new file mode 100644 index 0000000000000000000000000000000000000000..45255f18ee313ad96d072e42f620b219315a8adf --- /dev/null +++ b/en/application-dev/device-usage-statistics/device-usage-statistics-use-guide.md @@ -0,0 +1,534 @@ +# Device Usage Statistics Development (API Version 9) + +## When to Use + +With device usage statistics APIs, you can have a better understanding of the application, notification, and system usage. For example, in application usage statistics, you can query the application usage, event log, and application group. +The application records (usage history statistics and event records) cached by components are updated to the database for persistent storage within 30 minutes after an event is reported. + +## Available APIs +Import the **stats** package to implement registration: +```js +import usageStatistics from '@ohos.resourceschedule.usageStatistics'; +``` + +**Table 1** Major APIs for device usage statistics + +| API| Description| +| -------- | -------- | +| function queryBundleEvents(begin: number, end: number, callback: AsyncCallback<Array<BundleEvents>>): void | Queries events of all applications based on the specified start time and end time.| +| function queryBundleStatsInfos(begin: number, end: number, callback: AsyncCallback<BundleStatsMap>): void | Queries the application usage duration statistics based on the specified start time and end time.| +| function queryCurrentBundleEvents(begin: number, end: number, callback: AsyncCallback<Array<BundleEvents>>): void | Queries events of this application based on the specified start time and end time.| +| function queryBundleStatsInfoByInterval(byInterval: IntervalType, begin: number, end: number, callback: AsyncCallback<Array<BundleStatsInfo>>): void | Queries the application usage duration statistics in the specified time frame at the specified interval (daily, weekly, monthly, or annually).| +| function queryAppGroup(callback: AsyncCallback<number>): void | Queries the priority group of this application. This API uses an asynchronous callback to return the result.| +| function queryAppGroup(): Promise<number>; | Queries the priority group of this application. This API uses a promise to return the result.| +| function queryAppGroup(bundleName : string, callback: AsyncCallback<number>): void | Queries the priority group of the application specified by **bundleName**. This API uses an asynchronous callback to return the result.| +| function queryAppGroup(bundleName : string): Promise<number>; | Queries the priority group of the application specified by **bundleName**. If **bundleName** is not specified, the priority group of the current application is queried. This API uses a promise to return the result.| +| function isIdleState(bundleName: string, callback: AsyncCallback<boolean>): void | Checks whether the application specified by **bundleName** is in the idle state. | +| function queryModuleUsageRecords(callback: AsyncCallback<HapModuleInfo>): void | Obtains a maximum of 1000 FA usage records.| +| function queryModuleUsageRecords(maxNum: number, callback: AsyncCallback<HapModuleInfo>): void | Obtains the number of FA usage records specified by **maxNum**, which cannot exceed 1000.| +| function queryNotificationEventStats(begin: number, end: number, callback: AsyncCallback<Array<DeviceEventStats>>): void | Queries the number of notifications from all applications based on the specified start time and end time.| +| function queryDeviceEventStats(begin: number, end: number, callback: AsyncCallback<Array<DeviceEventStats>>): void | Queries statistics about system events (hibernation, wakeup, unlocking, and screen locking) that occur between the specified start time and end time.| +| function setAppGroup(bundleName : string, newGroup: GroupType, callback: AsyncCallback>boolean>): void | Sets the group for the application specified by **bundleName**. This API uses an asynchronous callback to return the result.| +| function setAppGroup(bundleName : string, newGroup : GroupType): Promise>boolean>; | Sets the group for the application specified by **bundleName**. This API uses a promise to return the result.| +| function registerAppGroupCallBack(groupCallback: Callback>AppGroupCallbackInfo>, callback: AsyncCallback>boolean>): void | Registers a callback for application group changes. When an application group of the user changes, the change is returned to all applications that have registered the callback. This API uses an asynchronous callback to return the result.| +| function registerAppGroupCallBack(groupCallback: Callback>AppGroupCallbackInfo>): Promise>boolean>; | Registers a callback for application group changes. When an application group of the user changes, the change is returned to all applications that have registered the callback. This API uses a promise to return the result.| +| function unregisterAppGroupCallBack(callback: AsyncCallback>boolean>): void | Deregisters the callback for application group changes. This API uses an asynchronous callback to return the result.| +| function unregisterAppGroupCallBack(): Promise>boolean>; | Deregisters the callback for application group changes. This API uses a promise to return the result.| + +## How to Develop + +1. Before obtaining the device usage statistics, check whether the **ohos.permission.BUNDLE_ACTIVE_INFO** permission is configured. For details about how to configure a permission, see [Declaring Permissions](../security/accesstoken-guidelines.md). + +2. Query events of all applications based on the specified start time and end time. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured. + + ```js + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // Promise mode + try{ + usageStatistics.queryBundleEvents(0, 20000000000000).then( res => { + console.log('BUNDLE_ACTIVE queryBundleEvents promise success.'); + for (let i = 0; i < res.length; i++) { + console.log('BUNDLE_ACTIVE queryBundleEvents promise number : ' + (i + 1)); + console.log('BUNDLE_ACTIVE queryBundleEvents promise result ' + JSON.stringify(res[i])); + } + }).catch( err => { + console.log('BUNDLE_ACTIVE queryBundleEvents promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryBundleEvents throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Asynchronous callback mode + try{ + usageStatistics.queryBundleEvents(0, 20000000000000, (err, res) => { + if (err) { + console.log('BUNDLE_ACTIVE queryBundleEvents callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE queryBundleEvents callback success.'); + for (let i = 0; i < res.length; i++) { + console.log('BUNDLE_ACTIVE queryBundleEvents callback number : ' + (i + 1)); + console.log('BUNDLE_ACTIVE queryBundleEvents callback result ' + JSON.stringify(res[i])); + } + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryBundleEvents throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` + +3. Query the application usage duration statistics based on the specified start time and end time. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured. + + ```js + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // Promise mode + try{ + usageStatistics.queryBundleStatsInfos(0, 20000000000000).then( res => { + console.log('BUNDLE_ACTIVE queryBundleStatsInfos promise success.'); + let i = 1; + for(let key in res){ + console.log('BUNDLE_ACTIVE queryBundleStatsInfos promise number : ' + i); + console.log('BUNDLE_ACTIVE queryBundleStatsInfos promise result ' + JSON.stringify(res[key])); + i++; + } + }).catch( err => { + console.log('BUNDLE_ACTIVE queryBundleStatsInfos promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryBundleStatsInfos throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Asynchronous callback mode + try{ + usageStatistics.queryBundleStatsInfos(0, 20000000000000, (err, res) => { + if (err) { + console.log('BUNDLE_ACTIVE queryBundleStatsInfos callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE queryBundleStatsInfos callback success.'); + let i = 1; + for(let key in res){ + console.log('BUNDLE_ACTIVE queryBundleStatsInfos callback number : ' + i); + console.log('BUNDLE_ACTIVE queryBundleStatsInfos callback result ' + JSON.stringify(res[key])); + i++; + } + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryBundleStatsInfos throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` + +4. Query events of this application based on the specified start time and end time. This requires no permission to be configured. + + ```js + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // Promise mode + try{ + usageStatistics.queryCurrentBundleEvents(0, 20000000000000).then( res => { + console.log('BUNDLE_ACTIVE queryCurrentBundleEvents promise success.'); + for (let i = 0; i < res.length; i++) { + console.log('BUNDLE_ACTIVE queryCurrentBundleEvents promise number : ' + (i + 1)); + console.log('BUNDLE_ACTIVE queryCurrentBundleEvents promise result ' + JSON.stringify(res[i])); + } + }).catch( err => { + console.log('BUNDLE_ACTIVE queryCurrentBundleEvents promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryCurrentBundleEvents throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Asynchronous callback mode + try{ + usageStatistics.queryCurrentBundleEvents(0, 20000000000000, (err, res) => { + if (err) { + console.log('BUNDLE_ACTIVE queryCurrentBundleEvents callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE queryCurrentBundleEvents callback success.'); + for (let i = 0; i < res.length; i++) { + console.log('BUNDLE_ACTIVE queryCurrentBundleEvents callback number : ' + (i + 1)); + console.log('BUNDLE_ACTIVE queryCurrentBundleEvents callback result ' + JSON.stringify(res[i])); + } + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryCurrentBundleEvents throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` + +5. Query the application usage duration statistics in the specified time frame at the specified interval (daily, weekly, monthly, or annually). This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured. + + ```js + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // Promise mode + try{ + usageStatistics.queryBundleStatsInfoByInterval(0, 0, 20000000000000).then( res => { + console.log('BUNDLE_ACTIVE queryBundleStatsInfoByInterval promise success.'); + for (let i = 0; i < res.length; i++) { + console.log('BUNDLE_ACTIVE queryBundleStatsInfoByInterval promise number : ' + (i + 1)); + console.log('BUNDLE_ACTIVE queryBundleStatsInfoByInterval promise result ' + JSON.stringify(res[i])); + } + }).catch( err => { + console.log('BUNDLE_ACTIVE queryBundleStatsInfoByInterval promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryBundleStatsInfoByInterval throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Asynchronous callback mode + try{ + usageStatistics.queryBundleStatsInfoByInterval(0, 0, 20000000000000, (err, res) => { + if (err) { + console.log('BUNDLE_ACTIVE queryBundleStatsInfoByInterval callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE queryBundleStatsInfoByInterval callback success.'); + for (let i = 0; i < res.length; i++) { + console.log('BUNDLE_ACTIVE queryBundleStatsInfoByInterval callback number : ' + (i + 1)); + console.log('BUNDLE_ACTIVE queryBundleStatsInfoByInterval callback result ' + JSON.stringify(res[i])); + } + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryBundleStatsInfoByInterval throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` + +6. Query the priority group of the current application. This requires no permission to be configured. + + ```js + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // Promise mode + try{ + usageStatistics.queryAppGroup().then( res => { + console.log('BUNDLE_ACTIVE queryAppGroup promise succeeded. result: ' + JSON.stringify(res)); + }).catch( err => { + console.log('BUNDLE_ACTIVE queryAppGroup promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryAppGroup throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Callback mode + try{ + usageStatistics.queryAppGroup((err, res) => { + if(err) { + console.log('BUNDLE_ACTIVE queryAppGroup callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE queryAppGroup callback succeeded. result: ' + JSON.stringify(res)); + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryAppGroup throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` + +7. Check whether the application specified by **bundleName** is in the idle state. This requires no permission to be configured. A third-party application can only check the idle status of itself. + + ```js + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // Promise mode + try{ + usageStatistics.isIdleState("com.ohos.camera").then( res => { + console.log('BUNDLE_ACTIVE isIdleState promise succeeded, result: ' + JSON.stringify(res)); + }).catch( err => { + console.log('BUNDLE_ACTIVE isIdleState promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE isIdleState throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Asynchronous callback mode + try{ + usageStatistics.isIdleState("com.ohos.camera", (err, res) => { + if (err) { + console.log('BUNDLE_ACTIVE isIdleState callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE isIdleState callback succeeded, result: ' + JSON.stringify(res)); + } + }); + } catch(error) { + console.log('BUNDLE_ACTIVE isIdleState throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` + +8. Obtain the number of FA usage records specified by **maxNum**. If **maxNum** is not specified, the default value **1000** is used. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured. + + ```js + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // Promise mode + try{ + usageStatistics.queryModuleUsageRecords(1000).then( res => { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords promise succeeded'); + for (let i = 0; i < res.length; i++) { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords promise number : ' + (i + 1)); + console.log('BUNDLE_ACTIVE queryModuleUsageRecords promise result ' + JSON.stringify(res[i])); + } + }).catch( err=> { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Promise mode when maxNum is not specified + try{ + usageStatistics.queryModuleUsageRecords().then( res => { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords promise succeeded'); + for (let i = 0; i < res.length; i++) { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords promise number : ' + (i + 1)); + console.log('BUNDLE_ACTIVE queryModuleUsageRecords promise result ' + JSON.stringify(res[i])); + } + }).catch( err=> { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Asynchronous callback mode + try{ + usageStatistics.queryModuleUsageRecords(1000, (err, res) => { + if(err) { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords callback succeeded.'); + for (let i = 0; i < res.length; i++) { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords callback number : ' + (i + 1)); + console.log('BUNDLE_ACTIVE queryModuleUsageRecords callback result ' + JSON.stringify(res[i])); + } + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Asynchronous callback mode when maxNum is not specified + try{ + usageStatistics.queryModuleUsageRecords((err, res) => { + if(err) { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords callback succeeded.'); + for (let i = 0; i < res.length; i++) { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords callback number : ' + (i + 1)); + console.log('BUNDLE_ACTIVE queryModuleUsageRecords callback result ' + JSON.stringify(res[i])); + } + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryModuleUsageRecords throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` + +9. Query the number of notifications from all applications based on the specified start time and end time. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured. + + ```js + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // Promise mode + try{ + usageStatistics.queryNotificationEventStats(0, 20000000000000).then( res => { + console.log('BUNDLE_ACTIVE queryNotificationEventStats promise success.'); + console.log('BUNDLE_ACTIVE queryNotificationEventStats promise result ' + JSON.stringify(res)); + }).catch( err=> { + console.log('BUNDLE_ACTIVE queryNotificationEventStats promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryNotificationEventStats throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Asynchronous callback mode + try{ + usageStatistics.queryNotificationEventStats(0, 20000000000000, (err, res) => { + if(err) { + console.log('BUNDLE_ACTIVE queryNotificationEventStats callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE queryNotificationEventStats callback success.'); + console.log('BUNDLE_ACTIVE queryNotificationEventStats callback result ' + JSON.stringify(res)); + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryNotificationEventStats throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` + +10. Query statistics about system events (hibernation, wakeup, unlocking, and screen locking) that occur between the specified start time and end time. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured. + + ```js + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // Promise mode + try{ + usageStatistics.queryDeviceEventStats(0, 20000000000000).then( res => { + console.log('BUNDLE_ACTIVE queryDeviceEventStates promise success.'); + console.log('BUNDLE_ACTIVE queryDeviceEventStates promise result ' + JSON.stringify(res)); + }).catch( err=> { + console.log('BUNDLE_ACTIVE queryDeviceEventStats promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryDeviceEventStats throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Asynchronous callback mode + try{ + usageStatistics.queryDeviceEventStats(0, 20000000000000, (err, res) => { + if(err) { + console.log('BUNDLE_ACTIVE queryDeviceEventStats callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE queryDeviceEventStats callback success.'); + console.log('BUNDLE_ACTIVE queryDeviceEventStats callback result ' + JSON.stringify(res)); + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryDeviceEventStats throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` + +11. Query the priority group of the application specified by **bundleName**. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured. + + ```js + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // Promise mode when bundleName is specified + let bundleName = "com.ohos.camera"; + try{ + usageStatistics.queryAppGroup(bundleName).then( res => { + console.log('BUNDLE_ACTIVE queryAppGroup promise succeeded. result: ' + JSON.stringify(res)); + }).catch( err => { + console.log('BUNDLE_ACTIVE queryAppGroup promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryAppGroup throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Asynchronous callback mode when bundleName is specified + let bundleName = "com.ohos.camera"; + try{ + usageStatistics.queryAppGroup(bundleName, (err, res) => { + if(err) { + console.log('BUNDLE_ACTIVE queryAppGroup callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE queryAppGroup callback succeeded. result: ' + JSON.stringify(res)); + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE queryAppGroup throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` + +12. Set the priority group of for application specified by **bundleName**. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured. + + ```javascript + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // Promise mode + let bundleName = "com.example.deviceUsageStatistics"; + let newGroup = bundleState.GroupType.ACTIVE_GROUP_DAILY; + + try{ + usageStatistics.setAppGroup(bundleName, newGroup).then( () => { + console.log('BUNDLE_ACTIVE setAppGroup promise succeeded.'); + }).catch( err => { + console.log('BUNDLE_ACTIVE setAppGroup promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE setAppGroup throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Asynchronous callback mode + let bundleName = "com.example.deviceUsageStatistics"; + let newGroup = bundleState.GroupType.ACTIVE_GROUP_DAILY; + + try{ + usageStatistics.setAppGroup(bundleName, newGroup, (err) => { + if(err) { + console.log('BUNDLE_ACTIVE setAppGroup callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE setAppGroup callback succeeded.'); + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE setAppGroup throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` + +13. Register a callback for application group changes. When an application group of the user changes, the change is returned to all applications that have registered the callback. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured. + + ```javascript + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // Promise mode + let onBundleGroupChanged = (res) =>{ + console.log('BUNDLE_ACTIVE registerAppGroupCallBack RegisterGroupCallBack callback success.'); + console.log('BUNDLE_ACTIVE registerAppGroupCallBack result appOldGroup is : ' + res.appOldGroup); + console.log('BUNDLE_ACTIVE registerAppGroupCallBack result appNewGroup is : ' + res.appNewGroup); + console.log('BUNDLE_ACTIVE registerAppGroupCallBack result changeReason is : ' + res.changeReason); + console.log('BUNDLE_ACTIVE registerAppGroupCallBack result userId is : ' + res.userId); + console.log('BUNDLE_ACTIVE registerAppGroupCallBack result bundleName is : ' + res.bundleName); + }; + try{ + usageStatistics.registerAppGroupCallBack(onBundleGroupChanged).then( () => { + console.log('BUNDLE_ACTIVE registerAppGroupCallBack promise succeeded.'); + }).catch( err => { + console.log('BUNDLE_ACTIVE registerAppGroupCallBack promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE registerAppGroupCallBack throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // Asynchronous callback mode + let onBundleGroupChanged = (err, res) =>{ + console.log('BUNDLE_ACTIVE onBundleGroupChanged RegisterGroupCallBack callback success.'); + console.log('BUNDLE_ACTIVE registerAppGroupCallBack result appOldGroup is : ' + res.appOldGroup); + console.log('BUNDLE_ACTIVE registerAppGroupCallBack result appNewGroup is : ' + res.appNewGroup); + console.log('BUNDLE_ACTIVE registerAppGroupCallBack result changeReason is : ' + res.changeReason); + console.log('BUNDLE_ACTIVE registerAppGroupCallBack result userId is : ' + res.userId); + console.log('BUNDLE_ACTIVE registerAppGroupCallBack result bundleName is : ' + res.bundleName); + }; + try{ + usageStatistics.registerAppGroupCallBack(onBundleGroupChanged, err => { + if(err) { + console.log('BUNDLE_ACTIVE registerAppGroupCallBack callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE registerAppGroupCallBack callback success.'); + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE registerAppGroupCallBack throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` + +14. Deregister the callback for application group changes. This requires the **ohos.permission.BUNDLE_ACTIVE_INFO** permission to be configured. + + ```javascript + import usageStatistics from '@ohos.resourceschedule.usageStatistics' + + // promise + try{ + usageStatistics.unregisterAppGroupCallBack().then( () => { + console.log('BUNDLE_ACTIVE unregisterAppGroupCallBack promise succeeded.'); + }).catch( err => { + console.log('BUNDLE_ACTIVE unregisterAppGroupCallBack promise failed. code is: ' + err.code + ',message is: ' + err.message); + }); + } catch (error) { + console.log('BUNDLE_ACTIVE unregisterAppGroupCallBack throw error, code is: ' + error.code + ',message is: ' + error.message); + } + + // callback + try{ + usageStatistics.unregisterAppGroupCallBack(err => { + if(err) { + console.log('BUNDLE_ACTIVE unregisterAppGroupCallBack callback failed. code is: ' + err.code + ',message is: ' + err.message); + } else { + console.log('BUNDLE_ACTIVE unregisterAppGroupCallBack callback success.'); + } + }); + } catch (error) { + console.log('BUNDLE_ACTIVE unregisterAppGroupCallBack throw error, code is: ' + error.code + ',message is: ' + error.message); + } + ``` \ No newline at end of file diff --git a/en/application-dev/device/Readme-EN.md b/en/application-dev/device/Readme-EN.md index c006438a34418139129e23f475d059e274ca914d..3c9f32cc174afcf03d5c35497dc56b24d79acc92 100644 --- a/en/application-dev/device/Readme-EN.md +++ b/en/application-dev/device/Readme-EN.md @@ -13,6 +13,9 @@ - Vibrator - [Vibrator Overview](vibrator-overview.md) - [Vibrator Development](vibrator-guidelines.md) +- Multimodal Input + - [Input Device Development](inputdevice-guidelines.md) + - [Mouse Pointer Development](pointerstyle-guidelines.md) - Update Service - [Sample Server Overview](sample-server-overview.md) - [Sample Server Development](sample-server-guidelines.md) diff --git a/en/application-dev/device/device-location-info.md b/en/application-dev/device/device-location-info.md index 4c51f50e9c29c9df846011e80c06a46a59045794..a153f69fbfe2b71362a4b7e5808fe57c1b7a4216 100644 --- a/en/application-dev/device/device-location-info.md +++ b/en/application-dev/device/device-location-info.md @@ -66,25 +66,7 @@ To learn more about the APIs for obtaining device location information, see [Geo If your application needs to access the device location information when running on the background, it must be configured to be able to run on the background and be granted the **ohos.permission.LOCATION_IN_BACKGROUND** permission. In this way, the system continues to report device location information after your application moves to the background. - To allow your application to access device location information, declare the required permissions in the **module.json** file of your application. The sample code is as follows: - - - ``` - { - "module": { - "reqPermissions": [ - "name": "ohos.permission.LOCATION", - "reason": "$string:reason_description", - "usedScene": { - "ability": ["com.myapplication.LocationAbility"], - "when": "inuse" - } - ] - } - } - ``` - - For details about these fields, see [Application Package Structure Configuration File](../quick-start/stage-structure.md). + You can declare the required permission in your application's configuration file. For details, see [Access Control (Permission) Development](../security/accesstoken-guidelines.md). 2. Import the **geolocation** module by which you can implement all APIs related to the basic location capabilities. diff --git a/en/application-dev/device/device-location-overview.md b/en/application-dev/device/device-location-overview.md index aa619c4549083521dd6ac5bcc05795074adc9af4..a26f0c5a7003a14c13cf4fc697e3a55a202f1eec 100644 --- a/en/application-dev/device/device-location-overview.md +++ b/en/application-dev/device/device-location-overview.md @@ -15,15 +15,18 @@ Your application can call location-specific APIs to obtain the location informat Location awareness helps determine where a mobile device locates. The system identifies the location of a mobile device with its coordinates, and uses location technologies such as Global Navigation Satellite System (GNSS) and network positioning (for example, base station positioning or WLAN/Bluetooth positioning) to provide diverse location-based services. These advanced location technologies make it possible to obtain the accurate location of the mobile device, regardless of whether it is indoors or outdoors. - **Coordinate** + A coordinate describes a location on the earth using the longitude and latitude in reference to the World Geodetic Coordinate System 1984. - **GNSS positioning** GNSS positioning locates a mobile device by using the location algorithm offered by the device chip to compute the location information provided by the Global Navigation Satellite System, for example, GPS, GLONASS, BeiDou, and Galileo. Whichever positioning system will be used during the location process depends on a hardware capability of the device. - **Base station positioning** + Base station positioning estimates the current location of a mobile device based on the location of the resident base station in reference to the neighboring base stations. This technology provides only a low accuracy and requires access to the cellular network. - **WLAN or Bluetooth positioning** + WLAN or Bluetooth positioning estimates the current location of a mobile device based on the locations of WLANs and Bluetooth devices that can be discovered by the device. The location accuracy of this technology depends on the distribution of fixed WLAN access points (APs) and Bluetooth devices around the device. A high density of WLAN APs and Bluetooth devices can produce a more accurate location result than base station positioning. This technology also requires access to the network. diff --git a/en/application-dev/device/figures/171e6f30-a8d9-414c-bafa-b430340305fb.png b/en/application-dev/device/figures/171e6f30-a8d9-414c-bafa-b430340305fb.png new file mode 100644 index 0000000000000000000000000000000000000000..69f6ef8876372f96ca0e75b286e300e39926956e Binary files /dev/null and b/en/application-dev/device/figures/171e6f30-a8d9-414c-bafa-b430340305fb.png differ diff --git a/en/application-dev/device/figures/65d69983-29f6-4381-80a3-f9ef2ec19e53.png b/en/application-dev/device/figures/65d69983-29f6-4381-80a3-f9ef2ec19e53.png new file mode 100644 index 0000000000000000000000000000000000000000..9ca04f490e6d0458cac72285945642d29efe6663 Binary files /dev/null and b/en/application-dev/device/figures/65d69983-29f6-4381-80a3-f9ef2ec19e53.png differ diff --git a/en/application-dev/device/figures/db5d017d-6c1c-4a71-a2dd-f74b7f23239e.png b/en/application-dev/device/figures/db5d017d-6c1c-4a71-a2dd-f74b7f23239e.png new file mode 100644 index 0000000000000000000000000000000000000000..2b55e6c8bf6456717b584c972e291f915b1c8ba1 Binary files /dev/null and b/en/application-dev/device/figures/db5d017d-6c1c-4a71-a2dd-f74b7f23239e.png differ diff --git a/en/application-dev/device/inputdevice-guidelines.md b/en/application-dev/device/inputdevice-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..1037520e553246d42d2da80f572637af310b4adc --- /dev/null +++ b/en/application-dev/device/inputdevice-guidelines.md @@ -0,0 +1,70 @@ +# Input Device Development + +## When to Use + +Input device management provides functions such as listening for device hot swap events and querying the keyboard type of a specified device. For example, as a user enters text, the input method determines whether to launch the virtual keyboard based on whether a physical keyboard is currently inserted. Your application can determine whether a physical keyboard is inserted by listening to device hot swap events. + +## Modules to Import + +```js +import inputDevice from '@ohos.multimodalInput.inputDevice'; +``` + +## Available APIs + +The following table lists the common APIs for input device management. For details about the APIs, see [ohos.multimodalInput.inputDevice](../reference/apis/js-apis-inputdevice.md). + +| Instance| API | Description| +| ----------- | ------------------------------------------------------------ | -------------------------- | +| inputDevice | function getDeviceList(callback: AsyncCallback\>): void; | Obtains the list of input devices.| +| inputDevice | function getKeyboardType(deviceId: number, callback: AsyncCallback\): void; | Obtains the keyboard type of the input device.| +| inputDevice | function on(type: "change", listener: Callback\): void; | Enables listening for device hot swap events.| +| inputDevice | function off(type: "change", listener?: Callback\): void; | Disables listening for device hot swap events.| + +## Virtual Keyboard Detection + +When a user enters text, the input method determines whether to launch the virtual keyboard based on whether a physical keyboard is currently inserted. Your application can determine whether a physical keyboard is inserted by listening to device hot swap events. + +## How to Develop + +1. Call the **getDeviceList** API to obtain the list of connected input devices. Call the **getKeyboardType** API to traverse all connected devices to check whether a physical keyboard exists. If a physical keyboard exists, mark the physical keyboard as connected. This step ensures that your application detects all inserted input devices before listening for device hot swap events. +2. Call the **on** API to listen for device hot swap events. If a physical keyboard is inserted, mark the physical keyboard as connected. If a physical keyboard is removed, mark the physical keyboard as disconnected. +3. When a user enters text, check whether a physical keyboard is connected. If a physical keyboard is not connected, launch the virtual keyboard. + + +```js +import inputDevice from '@ohos.multimodalInput.inputDevice'; + +let isPhysicalKeyboardExist = true; +try { + // 1. Obtain the list of input devices and check whether a physical keyboard is connected. + inputDevice.getDeviceList().then(data => { + for (let i = 0; i < data.length; ++i) { + inputDevice.getKeyboardType(data[i]).then(res => { + if (type == inputDevice.KeyboardType.ALPHABETIC_KEYBOARD) { + // The physical keyboard is connected. + isPhysicalKeyboardExist = true; + } + }); + } + }); + // 2. Listen for device hot swap events. + inputDevice.on("change", (data) => { + console.log(`Device event info: ${JSON.stringify(data)}`); + inputDevice.getKeyboardType(data.deviceId, (error, type) => { + console.log("The keyboard type is: " + type); + if (type == inputDevice.KeyboardType.ALPHABETIC_KEYBOARD && data.type == 'add') { + // The physical keyboard is inserted. + isPhysicalKeyboardExist = true; + } else if (type == inputDevice.KeyboardType.ALPHABETIC_KEYBOARD && data.type == 'remove') { + // The physical keyboard is removed. + isPhysicalKeyboardExist = false; + } + }); + }); +} catch (error) { + console.log(`Execute failed, error: ${JSON.stringify(error, [`code`, `message`])}`); +} + // 3. Determine whether to launch the virtual keyboard based on the value of isPhysicalKeyboardExist. + // TODO +``` diff --git a/en/application-dev/device/pointerstyle-guidelines.md b/en/application-dev/device/pointerstyle-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..d8ceab11829f1d5e717a61ec53ecfec19261226d --- /dev/null +++ b/en/application-dev/device/pointerstyle-guidelines.md @@ -0,0 +1,119 @@ +# Mouse Pointer Development + +## When to Use + +Mouse pointer management provides the functions such as displaying or hiding the mouse pointer as well as querying and setting the pointer style. For example, you can determine whether to display or hide the mouse pointer when a user watches a video in full screen, and can switch the mouse pointer to a color picker when a user attempts color pickup. + +## Modules to Import + +```js +import inputDevice from '@ohos.multimodalInput.pointer'; +``` + +## Available APIs + +The following table lists the common APIs for mouse pointer management. For details about the APIs, see [ohos.multimodalInput.pointer](../reference/apis/js-apis-pointer.md). + +| Instance | API | Description | +| ------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| pointer | function isPointerVisible(callback: AsyncCallback\): void; | Checks the visible status of the mouse pointer. | +| pointer | function setPointerVisible(visible: boolean, callback: AsyncCallback\): void; | Sets the visible status of the mouse pointer. This setting takes effect for the mouse pointer globally.| +| pointer | function setPointerStyle(windowId: number, pointerStyle: PointerStyle, callback: AsyncCallback\): void; | Sets the mouse pointer style. This setting takes effect for the mouse pointer style of a specified window. | +| pointer | function getPointerStyle(windowId: number, callback: AsyncCallback\): void; | Obtains the mouse pointer style. | + +## Hiding the Mouse Pointer + +When watching a video in full-screen mode, a user can hide the mouse pointer for an improved user experience. + +## How to Develop + +1. Switch to the full-screen playback mode. +2. Hide the mouse pointer. +3. Exit the full-screen playback mode. +4. Display the mouse pointer. + +```js +import pointer from '@ohos.multimodalInput.pointer'; + +// 1. Switch to the full-screen playback mode. +// 2. Hide the mouse pointer. +try { + pointer.setPointerVisible(false, (error) => { + if (error) { + console.log(`Set pointer visible failed, error: ${JSON.stringify(error, [`code`, `message`])}`); + return; + } + console.log(`Set pointer visible success.`); + }); +} catch (error) { + console.log(`The mouse pointer hide attributes is failed. ${JSON.stringify(error, [`code`, `message`])}`); +} + +// 3. Exit the full-screen playback mode. +// 4. Display the mouse pointer. +try { + pointer.setPointerVisible(true, (error) => { + if (error) { + console.log(`Set pointer visible failed, error: ${JSON.stringify(error, [`code`, `message`])}`); + return; + } + console.log(`Set pointer visible success.`); + }); +} catch (error) { + console.log(`Set pointer visible failed, ${JSON.stringify(error, [`code`, `message`])}`); +} +``` + +## Setting the Mouse Pointer Style + +When designing a color picker, you can have the mouse pointer switched to the color picker style during color pickup and then switched to the default style on completion of color pickup. This setting takes effect for the pointer style of a specified window in the current application. A total of 39 pointer styles can be set. For details, see [Pointer Style](../reference/apis/js-apis-pointer.md#pointerstyle9). + +### How to Develop + +1. Enable the color pickup function. +2. Obtain the window ID. +3. Set the mouse pointer to the color picker style. +4. End color pickup. +5. Set the mouse pointer to the default style. + +```js +import window from '@ohos.window'; + +// 1. Enable the color pickup function. +// 2. Obtain the window ID. +window.getTopWindow((error, windowClass) => { + windowClass.getProperties((error, data) => { + var windowId = data.id; + if (windowId < 0) { + console.log(`Invalid windowId`); + return; + } + try { + // 3. Set the mouse pointer to the color picker style. + pointer.setPointerStyle(windowId, pointer.PointerStyle.COLOR_SUCKER).then(() => { + console.log(`Successfully set mouse pointer style`); + }); + } catch (error) { + console.log(`Failed to set the pointer style, error=${JSON.stringify(error)}, msg=${JSON.stringify(message)}`); + } + }); +}); +// 4. End color pickup. +window.getTopWindow((error, windowClass) => { + windowClass.getProperties((error, data) => { + var windowId = data.id; + if (windowId < 0) { + console.log(`Invalid windowId`); + return; + } + try { + // 5. Set the mouse pointer to the default style. + pointer.setPointerStyle(windowId, pointer.PointerStyle.DEFAULT).then(() => { + console.log(`Successfully set mouse pointer style`); + }); + } catch (error) { + console.log(`Failed to set the pointer style, error=${JSON.stringify(error)}, msg=${JSON.stringify(message)}`); + } + }); +}); +``` diff --git a/en/application-dev/device/sample-server-guidelines.md b/en/application-dev/device/sample-server-guidelines.md index 383894cb87dfea65ee6291836bc1928f8341a479..369fb8cc31d3c86e96c42bb38aef2f67761eb9e4 100644 --- a/en/application-dev/device/sample-server-guidelines.md +++ b/en/application-dev/device/sample-server-guidelines.md @@ -2,7 +2,7 @@ ## When to Use -The sample server provides a package search server for checking update packages and obtaining the update package download URLs, which was previously unavailable in the real-world update service. The sample server supports update service testing and secondary development function verification, building an end-to-end environment to cater for diverse update service use cases. +The sample server provides a package search server for checking update packages and obtaining the update package download URLs, which was previously unavailable in the real-world update service. The sample server supports update service testing and functional verification for secondary development, building an end-to-end environment to cater for diverse update service use cases. ## How to Develop @@ -32,13 +32,13 @@ The sample server provides a package search server for checking update packages Go to the **update_updateservice** directory and run the following commands to create a code directory: ``` - mkdir server_sample // Create the server_sample folder. - touch server_sample/BUILD.gn // Create the BUILD.gn file. - mkdir server_sample/include // Create the include folder to store the header file of the sample server. - touch server_process.h // Create the server_process.h header file. - mkdir server_sample/src // Create the src folder to store the C/C++ files of the sample server. - touch server_sample/src/server_process.c // Create the server_process.c file. - touch server_sample/src/main.cpp // Create the main.cpp file. + mkdir server_sample // Create the server_sample folder. + touch server_sample/BUILD.gn // Create the BUILD.gn file. + mkdir server_sample/include // Create the include folder to store the header file of the sample server. + touch server_process.h // Create the server_process.h header file. + mkdir server_sample/src // Create the src folder to store the C/C++ files of the sample server. + touch server_sample/src/server_process.c // Create the server_process.c file. + touch server_sample/src/main.cpp // Create the main.cpp file. ``` 4. Write the **BUILD.gn** file. @@ -175,7 +175,7 @@ The sample server provides a package search server for checking update packages "\"descriptPackageId\": \"abcdefg1234567ABCDEFG\"," "}]," "\"descriptInfo\": [{" - "\"descriptPackageId\": \"abcdefg1234567ABCDEFG\"," + "\"descriptionType\": 0," "\"content\": \"This package message is used for sampleContent\"" "}]" "}"; diff --git a/en/application-dev/device/sample-server-overview.md b/en/application-dev/device/sample-server-overview.md index 6924f8d7f2256dff9ec828cc5fb62248f68599f1..9e31fe0b50a7d7641fde28ca16c252a97aa2d646 100644 --- a/en/application-dev/device/sample-server-overview.md +++ b/en/application-dev/device/sample-server-overview.md @@ -30,7 +30,7 @@ The following is an example of the JSON response returned by the server. Note th "descriptPackageId": "abcdefg1234567ABCDEFG" }], "descriptInfo": [{ - "descriptPackageId": "abcdefg1234567ABCDEFG", + "descriptionType": 0, "content": "This package is used for update." }] } diff --git a/en/application-dev/device/sensor-guidelines.md b/en/application-dev/device/sensor-guidelines.md index 50ebd3428f89eba4f968dd98e5fe2edee91bee34..d3bb893bbbdf1c23192f3397e54d745cf920043c 100644 --- a/en/application-dev/device/sensor-guidelines.md +++ b/en/application-dev/device/sensor-guidelines.md @@ -3,30 +3,18 @@ ## When to Use -- Data provided by the compass sensor denotes the current orientation of the user device, which helps your application accurately navigate for the user. +With the sensor module, a device can obtain sensor data. For example, the device can subscribe to data of the orientation sensor to detect its own orientation, and data of the pedometer sensor to learn the number of steps the user walks every day. -- Data provided by the proximity sensor denotes the distance between the device and a visible object, which enables the device to automatically turn on or off its screen accordingly to prevent accidental touch on the screen. - -- Data provided by the barometer sensor helps your application accurately determine the altitude of the device. - -- Data provided by the ambient light sensor helps your device automatically adjust its backlight. - -- Data provided by the Hall effect sensor implements the smart cover mode of your device. - -- Data provided by the heart rate sensor helps your application track the heart health of a user. - -- Data provided by the pedometer sensor helps your application obtain the number of steps a user has walked. - -- Data provided by the wear detection sensor helps your application detect whether a user is wearing a wearable device. +For details about the APIs, see [Sensor](../reference/apis/js-apis-sensor.md). ## Available APIs | Module| API| Description| | -------- | -------- | -------- | -| ohos.sensor | sensor.on(sensorType, callback:AsyncCallback<Response>): void | Subscribes to data changes of a type of sensor.| -| ohos.sensor | sensor.once(sensorType, callback:AsyncCallback<Response>): void | Subscribes to only one data change of a type of sensor.| -| ohos.sensor | sensor.off(sensorType, callback?:AsyncCallback<void>): void | Unsubscribes from sensor data changes.| +| ohos.sensor | sensor.on(sensorId, callback:AsyncCallback<Response>): void | Subscribes to data changes of a type of sensor.| +| ohos.sensor | sensor.once(sensorId, callback:AsyncCallback<Response>): void | Subscribes to only one data change of a type of sensor.| +| ohos.sensor | sensor.off(sensorId, callback?:AsyncCallback<void>): void | Unsubscribes from sensor data changes.| ## How to Develop @@ -43,52 +31,46 @@ For details about how to configure a permission, see [Declaring Permissions](../security/accesstoken-guidelines.md). -2. Subscribe to data changes of a type of sensor. +2. Subscribe to data changes of a type of sensor. The following uses the acceleration sensor as an example. - ``` + ```js import sensor from "@ohos.sensor"; - sensor.on(sensor.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, function(data){ + sensor.on(sensor.SensorId.ACCELEROMETER, function(data){ console.info("Data obtained successfully. x: " + data.x + "y: " + data.y + "z: " + data.z); // Data is obtained. }); ``` - The following figure shows the successful call result when **SensorType** is **SENSOR_TYPE_ID_ACCELEROMETER**. - - ![en-us_image_0000001241693881](figures/en-us_image_0000001241693881.png) + ![171e6f30-a8d9-414c-bafa-b430340305fb](figures/171e6f30-a8d9-414c-bafa-b430340305fb.png) 3. Unsubscribe from sensor data changes. - ``` + ```js import sensor from "@ohos.sensor"; - sensor.off(sensor.SensorType.SENSOR_TYPE_ID_ACCELEROMETER); + sensor.off(sensor.SensorId.ACCELEROMETER); ``` - The following figure shows the successful call result when **SensorType** is **SENSOR_TYPE_ID_ACCELEROMETER**. - - ![en-us_image_0000001196654004](figures/en-us_image_0000001196654004.png) + ![65d69983-29f6-4381-80a3-f9ef2ec19e53](figures/65d69983-29f6-4381-80a3-f9ef2ec19e53.png) 4. Subscribe to only one data change of a type of sensor. - ``` + ```js import sensor from "@ohos.sensor"; - sensor.once(sensor.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, function(data) { + sensor.once(sensor.SensorId.ACCELEROMETER, function(data) { console.info("Data obtained successfully. x: " + data.x + "y: " + data.y + "z: " + data.z); // Data is obtained. }); ``` - The following figure shows the successful call result when **SensorType** is **SENSOR_TYPE_ID_ACCELEROMETER**. - - ![en-us_image_0000001241733907](figures/en-us_image_0000001241733907.png) + ![db5d017d-6c1c-4a71-a2dd-f74b7f23239e](figures/db5d017d-6c1c-4a71-a2dd-f74b7f23239e.png) If the API fails to be called, you are advised to use the **try/catch** statement to capture error information that may occur in the code. Example: - ``` + ```js import sensor from "@ohos.sensor"; try { - sensor.once(sensor.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, function(data) { + sensor.once(sensor.SensorId.ACCELEROMETER, function(data) { console.info("Data obtained successfully. x: " + data.x + "y: " + data.y + "z: " + data.z); // Data is obtained. }); } catch (error) { - console.error("Failed to get sensor data"); + console.error("Get sensor data error. data:" + error.data, " msg:", error.message); } - ``` \ No newline at end of file + ``` diff --git a/en/application-dev/device/sensor-overview.md b/en/application-dev/device/sensor-overview.md index cb6129928d3796779075bcfc28da7f606bd130d9..766cc71c2aa466903a27a6b2bcb2d065bab74f54 100644 --- a/en/application-dev/device/sensor-overview.md +++ b/en/application-dev/device/sensor-overview.md @@ -3,32 +3,29 @@ Sensors in OpenHarmony are an abstraction of underlying sensor hardware. Your application can access the underlying sensor hardware via the sensors. Using the [Sensor](../reference/apis/js-apis-sensor.md) APIs, you can query sensors on your device, subscribe to sensor data, customize algorithms based on sensor data, and develop various sensor-based applications, such as compass, motion-controlled games, and fitness and health applications. - -A sensor is a device to detect events or changes in an environment and send messages about the events or changes to another device (for example, a CPU). Generally, a sensor is composed of sensitive components and conversion components. Sensors are the cornerstone of the IoT. A unified sensor management framework is required to achieve data sensing at a low latency and low power consumption, thereby keeping up with requirements of "1+8+N" products or business in the Seamless AI Life Strategy. The sensor list is as follows: - -| Type | Name | Description | Usage | -| --------------------------------------- | --------- | ---------------------------------------- | -------------------- | -| SENSOR_TYPE_ACCELEROMETER | Acceleration sensor | Measures the acceleration (including the gravity acceleration) applied to a device on three physical axes (X, Y, and Z), in the unit of m/s2.| Detecting the motion status | -| SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED | Uncalibrated acceleration sensor| Measures the uncalibrated acceleration (including the gravity acceleration) applied to a device on three physical axes (X, Y, and Z), in the unit of m/s2.| Measuring the acceleration bias estimation | -| SENSOR_TYPE_LINEAR_ACCELERATION | Linear acceleration sensor | Measures the linear acceleration (excluding the gravity acceleration) applied to a device on three physical axes (X, Y, and Z), in the unit of m/s2.| Detecting the linear acceleration in each axis | -| SENSOR_TYPE_GRAVITY | Gravity sensor | Measures the gravity acceleration applied to a device on three physical axes (X, Y, and Z), in the unit of m/s2.| Measuring the gravity | -| SENSOR_TYPE_GYROSCOPE | Gyroscope sensor | Measures the rotation angular velocity of a device on three physical axes (X, Y, and Z), in the unit of rad/s.| Measuring the rotation angular velocity | -| SENSOR_TYPE_GYROSCOPE_UNCALIBRATED | Uncalibrated gyroscope sensor| Measures the uncalibrated rotation angular velocity of a device on three physical axes (X, Y, and Z), in the unit of rad/s.| Measuring the bias estimation of the rotation angular velocity | -| SENSOR_TYPE_SIGNIFICANT_MOTION | Significant motion sensor | Checks whether a device has a significant motion on three physical axes (X, Y, and Z). The value **0** means that the device does not have a significant motion, and **1** means the opposite.| Detecting significant motions of a device | -| SENSOR_TYPE_PEDOMETER_DETECTION | Pedometer detection sensor | Detects whether a user takes a step. The value can be **0** (the user does not take a step) or **1** (the user takes a step).| Detecting whether a user takes a step | -| SENSOR_TYPE_PEDOMETER | Pedometer sensor | Records the number of steps a user has walked. | Providing the number of steps a user has walked | -| SENSOR_TYPE_AMBIENT_TEMPERATURE | Ambient temperature sensor | Measures the ambient temperature, in the unit of degree Celsius (°C). | Measuring the ambient temperature | -| SENSOR_TYPE_MAGNETIC_FIELD | Magnetic field sensor | Measures the magnetic field on three physical axes (X, Y, and Z), in the unit of μT.| Creating a compass | -| SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED | Uncalibrated magnetic field sensor | Measures the uncalibrated magnetic field on three physical axes (X, Y, and Z), in the unit of μT.| Measuring the magnetic field bias estimation | -| SENSOR_TYPE_HUMIDITY | Humidity sensor | Measures the ambient relative humidity, in a percentage (%). | Monitoring the dew point, absolute humidity, and relative humidity | -| SENSOR_TYPE_BAROMETER | Barometer sensor | Measures the barometric pressure, in the unit of hPa or mbar.| Measuring the barometric pressure | -| SENSOR_TYPE_ORIENTATION | Orientation sensor | Measures the rotation angles of a device on three physical axes (X, Y, and Z), in the unit of rad. | Providing the three orientation angles of the screen | -| SENSOR_TYPE_ROTATION_VECTOR | Rotation vector sensor | Measures the rotation vector of a device. It is a composite sensor that generates data from the acceleration sensor, magnetic field sensor, and gyroscope sensor. | Detecting the orientation of a device in the East, North, Up (ENU) Cartesian coordinate system | -| SENSOR_TYPE_PROXIMITY | Proximity sensor | Measures the distance between a visible object and the device screen. | Measuring the distance between a person and the device during a call | -| SENSOR_TYPE_AMBIENT_LIGHT | Ambient light sensor | Measures the ambient light intensity of a device, in the unit of lux. | Automatically adjusting the screen brightness and checking whether the screen is covered on the top| -| SENSOR_TYPE_HEART_RATE | Heart rate sensor | Measures the heart rate of a user. | Providing users' heart rate data | -| SENSOR_TYPE_WEAR_DETECTION | Wear detection sensor | Checks whether a user is wearing a wearable device. | Detecting wearables | -| SENSOR_TYPE_HALL | Hall effect sensor | Detects a magnetic field around a device. | Smart cover mode of the device | +| Type | Name | Description | Usage | +| --------------------------- | ------------------ | ------------------------------------------------------------ | ---------------------------------------- | +| ACCELEROMETER | Acceleration sensor | Measures the acceleration (including the gravity acceleration) applied to a device on three physical axes (X, Y, and Z), in the unit of m/s2.| Detecting the motion status | +| ACCELEROMETER_UNCALIBRATED | Uncalibrated acceleration sensor| Measures the uncalibrated acceleration (including the gravity acceleration) applied to a device on three physical axes (X, Y, and Z), in the unit of m/s2.| Measuring the acceleration bias estimation | +| LINEAR_ACCELERATION | Linear acceleration sensor | Measures the linear acceleration (excluding the gravity acceleration) applied to a device on three physical axes (X, Y, and Z), in the unit of m/s2.| Detecting the linear acceleration in each axis | +| GRAVITY | Gravity sensor | Measures the gravity acceleration applied to a device on three physical axes (X, Y, and Z), in the unit of m/s2.| Measuring the gravity | +| GYROSCOPE | Gyroscope sensor | Measures the rotation angular velocity of a device on three physical axes (X, Y, and Z), in the unit of rad/s.| Measuring the rotation angular velocity | +| GYROSCOPE_UNCALIBRATED | Uncalibrated gyroscope sensor| Measures the uncalibrated rotation angular velocity of a device on three physical axes (X, Y, and Z), in the unit of rad/s.| Measuring the bias estimation of the rotation angular velocity | +| SIGNIFICANT_MOTION | Significant motion sensor | Checks whether a device has a significant motion on three physical axes (X, Y, and Z). The value **0** means that the device does not have a significant motion, and **1** means the opposite.| Detecting significant motions of a device | +| PEDOMETER_DETECTION | Pedometer detection sensor | Detects whether a user takes a step. The value can be **0** (the user does not take a step) or **1** (the user takes a step).| Detecting whether a user takes a step | +| PEDOMETER | Pedometer sensor | Records the number of steps a user has walked. | Providing the number of steps a user has walked | +| AMBIENT_TEMPERATURE | Ambient temperature sensor | Measures the ambient temperature, in the unit of degree Celsius (°C). | Measuring the ambient temperature | +| MAGNETIC_FIELD | Magnetic field sensor | Measures the magnetic field on three physical axes (X, Y, and Z), in the unit of μT.| Creating a compass | +| MAGNETIC_FIELD_UNCALIBRATED | Uncalibrated magnetic field sensor | Measures the uncalibrated magnetic field on three physical axes (X, Y, and Z), in the unit of μT.| Measuring the magnetic field bias estimation | +| HUMIDITY | Humidity sensor | Measures the ambient relative humidity, in a percentage (%). | Monitoring the dew point, absolute humidity, and relative humidity | +| BAROMETER | Barometer sensor | Measures the barometric pressure, in the unit of hPa or mbar. | Measuring the barometric pressure | +| ORIENTATION | Orientation sensor | Measures the rotation angles of a device on three physical axes (X, Y, and Z), in the unit of rad.| Providing the three orientation angles of the screen | +| ROTATION_VECTOR | Rotation vector sensor | Measures the rotation vector of a device. It is a composite sensor that generates data from the acceleration sensor, magnetic field sensor, and gyroscope sensor.| Detecting the orientation of a device in the East, North, Up (ENU) Cartesian coordinate system | +| PROXIMITY | Proximity sensor | Measures the distance between a visible object and the device screen. | Measuring the distance between a person and the device during a call | +| AMBIENT_LIGHT | Ambient light sensor | Measures the ambient light intensity of a device, in the unit of lux. | Automatically adjusting the screen brightness and checking whether the screen is covered on the top| +| HEART_RATE | Heart rate sensor | Measures the heart rate of a user. | Providing users' heart rate data | +| WEAR_DETECTION | Wear detection sensor | Checks whether a user is wearing a wearable device. | Detecting wearables | +| HALL | Hall effect sensor | Detects a magnetic field around a device. | Smart cover mode of the device | ## Working Principles @@ -60,4 +57,3 @@ The following modules work cooperatively to implement OpenHarmony sensors: Senso | Heart rate sensor | ohos.permission.READ_HEALTH_DATA | user_grant | Allows an application to read health data. | 2. The APIs for subscribing to and unsubscribing from sensor data work in pairs. If you do not need sensor data, call the unsubscription API to stop sensor data reporting. - diff --git a/en/application-dev/device/usb-guidelines.md b/en/application-dev/device/usb-guidelines.md index d51625ccb9605fe2fb35b95f71eebc4e1607b753..768866b4974eb59a81aa3d17f9d099d03fbdc415 100644 --- a/en/application-dev/device/usb-guidelines.md +++ b/en/application-dev/device/usb-guidelines.md @@ -2,7 +2,7 @@ ## When to Use -In Host mode, you can obtain the list of connected devices, enable or disable the devices, manage device access permissions, and perform data transfer or control transfer. +In Host mode, you can obtain the list of connected USB devices, enable or disable the devices, manage device access permissions, and perform data transfer or control transfer. ## APIs @@ -16,6 +16,7 @@ The following table lists the USB APIs currently available. For details, see the | ------------------------------------------------------------ | ------------------------------------------------------------ | | hasRight(deviceName: string): boolean | Checks whether the user, for example, the application or system, has the device access permissions. The value **true** is returned if the user has the device access permissions; the value **false** is returned otherwise. | | requestRight(deviceName: string): Promise\ | Requests the temporary permission for a given application to access the USB device. | +| removeRight(deviceName: string): boolean | Removes the permission for a given application to access the USB device. | | connectDevice(device: USBDevice): Readonly\ | Connects to the USB device based on the device information returned by `getDevices()`. | | getDevices(): Array> | Obtains the USB device list. | | setConfiguration(pipe: USBDevicePipe, config: USBConfig): number | Sets the USB device configuration. | @@ -38,7 +39,7 @@ You can set a USB device as the USB host to connect to other USB devices for dat // Import the USB API package. import usb from '@ohos.usb'; // Obtain the USB device list. - var deviceList = usb.getDevices(); + let deviceList = usb.getDevices(); /* Example deviceList structure [ @@ -81,21 +82,21 @@ You can set a USB device as the USB host to connect to other USB devices for dat number: 1, type: 3, interfaceId: 0, - }, - ], - }, - ], - }, - ], - }, - ], + } + ] + } + ] + } + ] + } + ] */ ``` 2. Obtain the device operation permissions. ```js - var deviceName = deviceList[0].name; + let deviceName = deviceList[0].name; // Request the permissions to operate a specified device. usb.requestRight(deviceName).then(hasRight => { console.info("usb device request right result: " + hasRight); @@ -108,7 +109,7 @@ You can set a USB device as the USB host to connect to other USB devices for dat ```js // Open the device, and obtain the USB device pipe for data transfer. - var pipe = usb.connectDevice(deviceList[0]); + let pipe = usb.connectDevice(deviceList[0]); /* Claim the corresponding interface from deviceList. interface1 must be one present in the device configuration. @@ -127,7 +128,7 @@ You can set a USB device as the USB host to connect to other USB devices for dat usb.bulkTransfer(pipe, inEndpoint, dataUint8Array, 15000).then(dataLength => { if (dataLength >= 0) { console.info("usb readData result Length : " + dataLength); - var resultStr = this.ab2str(dataUint8Array); // Convert uint8 data into a string. + let resultStr = this.ab2str(dataUint8Array); // Convert uint8 data into a string. console.info("usb readData buffer : " + resultStr); } else { console.info("usb readData failed : " + dataLength); diff --git a/en/application-dev/device/vibrator-guidelines.md b/en/application-dev/device/vibrator-guidelines.md index 0dfc8344e5bb27a7ab6b6cd11943595c9f7855a6..36b08b2acd96e2d65fc14a936f1c3e9c9dd31a88 100644 --- a/en/application-dev/device/vibrator-guidelines.md +++ b/en/application-dev/device/vibrator-guidelines.md @@ -10,42 +10,55 @@ For details about the APIs, see [Vibrator](../reference/apis/js-apis-vibrator.md ## Available APIs -| Module | API | Description | -| ------------- | ---------------------------------------- | ------------------------------- | -| ohos.vibrator | vibrate(duration: number): Promise<void> | Triggers vibration with the specified duration. This API uses a promise to return the result. | -| ohos.vibrator | vibrate(duration: number, callback?: AsyncCallback<void>): void | Triggers vibration with the specified duration. This API uses a callback to return the result. | -| ohos.vibrator | vibrate(effectId: EffectId): Promise<void> | Triggers vibration with the specified effect. This API uses a promise to return the result. | -| ohos.vibrator | vibrate(effectId: EffectId, callback?: AsyncCallback<void>): void | Triggers vibration with the specified effect. This API uses a callback to return the result.| -| ohos.vibrator | stop(stopMode: VibratorStopMode): Promise<void>| Stops vibration. This API uses a promise to return the result. | -| ohos.vibrator | stop(stopMode: VibratorStopMode, callback?: AsyncCallback<void>): void | Stops vibration. This API uses a callback to return the result. | +| Module | API | Description | +| ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| ohos.vibrator | startVibration(effect: VibrateEffect, attribute: VibrateAttribute): Promise<void> | Starts vibration with the specified effect and attribute. This API uses a promise to return the result.| +| ohos.vibrator | startVibration(effect: VibrateEffect, attribute: VibrateAttribute, callback: AsyncCallback<void>): void | Starts vibration with the specified effect and attribute. This API uses an asynchronous callback to return the result.| +| ohos.vibrator | stopVibration(stopMode: VibratorStopMode): Promise<void> | Stops vibration in the specified mode. This API uses a promise to return the result. | +| ohos.vibrator | stopVibration(stopMode: VibratorStopMode, callback: AsyncCallback<void>): void | Stops vibration in the specified mode. This API uses an asynchronous callback to return the result. | ## How to Develop 1. Before using the vibrator on a device, you must declare the **ohos.permission.VIBRATE** permission. For details about how to configure a permission, see [Declaring Permissions](../security/accesstoken-guidelines.md). -2. Trigger the device to vibrate. +2. Start vibration with the specified effect and attribute. - ``` - import vibrator from "@ohos.vibrator" - vibrator.vibrate(1000).then((error) => { - if (error) { // The call fails, and error.code and error.message are printed. - console.log("Promise return failed.error.code " + error.code + "error.message " + error.message); - } else { // The call is successful, and the device starts to vibrate. - console.log("Promise returned to indicate a successful vibration.") - } - }) + ```js + import vibrator from '@ohos.vibrator'; + try { + vibrator.startVibration({ + type: 'time', + duration: 1000, + }, { + id: 0, + usage: 'alarm' + }, (error) => { + if (error) { + console.error('vibrate fail, error.code: ' + error.code + 'error.message: ', + error.message); + return; + } + console.log('Callback returned to indicate a successful vibration.'); + }); + } catch (err) { + console.error('errCode: ' + err.code + ' ,msg: ' + err.message); + } ``` -3. Stop the vibration. +3. Stop vibration in the specified mode. - ``` - import vibrator from "@ohos.vibrator" - vibrator.stop(vibrator.VibratorStopMode.VIBRATOR_STOP_MODE_PRESET).then((error) => { - if (error) { // The call fails, and error.code and error.message are printed. - console.log("Promise return failed.error.code " + error.code + "error.message " + error.message); - } else { // The call is successful, and the device stops vibrating. - console.log("Promise returned to indicate successful."); - } - }) + ```js + import vibrator from '@ohos.vibrator'; + try { + // Stop vibration in VIBRATOR_STOP_MODE_TIME mode. + vibrator.stopVibration(vibrator.VibratorStopMode.VIBRATOR_STOP_MODE_TIME, function (error) { + if (error) { + console.log('error.code' + error.code + 'error.message' + error.message); + return; + } + console.log('Callback returned to indicate successful.'); + }) + } catch (err) { + console.info('errCode: ' + err.code + ' ,msg: ' + err.message); + } ``` diff --git a/en/application-dev/dfx/hiappevent-guidelines.md b/en/application-dev/dfx/hiappevent-guidelines.md index 48f725e080441281cd2e88820eeacc6032a2dbab..067b9b8c915417b93340ab55bf34a74bca422a3d 100644 --- a/en/application-dev/dfx/hiappevent-guidelines.md +++ b/en/application-dev/dfx/hiappevent-guidelines.md @@ -8,28 +8,20 @@ The event logging function helps applications log various information generated JS application event logging APIs are provided by the **hiAppEvent** module. -The following table provides only a brief description of related APIs. For details, see [HiAppEvent](../reference/apis/js-apis-hiappevent.md). +The following table provides only a brief description of related APIs. For details, see [HiAppEvent](../reference/apis/js-apis-hiviewdfx-hiappevent.md). **Table 1** APIs for application event logging -| API | Description | -| ------------------------------------------------------------ | ------------------------------------------------------------ | -| write(string eventName, EventType type, object keyValues, AsyncCallback\ callback): void | Logs application events in asynchronous mode. This API uses an asynchronous callback to return the result. | -| write(string eventName, EventType type, object keyValues): Promise\ | Logs application events in asynchronous mode. This API uses a promise to return the result. | -| write(AppEventInfo info, AsyncCallback\ callback): void | Logs application events by domain in asynchronous mode. This API uses an asynchronous callback to return the result.| -| write(AppEventInfo info): Promise\ | Logs application events by domain in asynchronous mode. This API uses a promise to return the result.| - -When an asynchronous callback is used, the return value can be processed directly in the callback. - -If a promise is used, the return value can also be processed in the promise in a similar way. - -For details about the result codes, see [Event Verification Result Codes](#event-verification-result-codes). +| API | Description | +| ------------------------------------------------------------ | ---------------------------------------------------- | +| write(AppEventInfo info, AsyncCallback\ callback): void | Logs application events in asynchronous mode. This API uses an asynchronous callback to return the result.| +| write(AppEventInfo info): Promise\ | Logs application events in asynchronous mode. This API uses a promise to return the result. | **Table 2** APIs for event logging configuration -| API | Description | -| --------------------------------------- | ---------------------------------------------------- | -| configure(ConfigOption config): boolean | Sets the configuration options for application event logging.| +| API | Description | +| ------------------------------------ | ---------------------------------------------------- | +| configure(ConfigOption config): void | Sets the configuration options for application event logging.| **Table 3** APIs for watcher management @@ -44,32 +36,14 @@ For details about the result codes, see [Event Verification Result Codes](#event | ----------------- | -------------------- | | clearData(): void | Clears local logging data.| -### Event Verification Result Codes - -| Result Code| Cause | Verification Rules | Handling Method | -| ------ | ----------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------- | -| 0 | N/A | Event verification is successful. | Event logging is normal. No action is required. | -| -1 | Invalid event name | The name is not empty and contains a maximum of 48 characters.
The name consists of only the following characters: digits (0 to 9), letters (a to z), and underscore \(_).
The name does not start with a digit or underscore \(_).| Ignore this event and do not perform logging. | -| -2 | Invalid event parameter type | The event name must be a string.
The event type must be a number.
The event parameter must be an object.| Ignore this event and do not perform logging. | -| -4 | Invalid event domain name | The name is not empty and contains a maximum of 32 characters.
The name consists of only the following characters: digits (0 to 9), letters (a to z), and underscore \(_).
The name does not start with a digit or underscore \(_).| Ignore this event and do not perform logging. | -| -99 | Application event logging disabled | Application event logging is disabled. | Ignore this event and do not perform logging. | -| -100 | Unknown error | None. | Ignore this event and do not perform logging. | -| 1 | Invalid key name | The name is not empty and contains a maximum of 16 characters.
The name consists of only the following characters: digits (0 to 9), letters (a to z), and underscore \(_).
The name does not start with a digit or underscore \(_).
The name does not end with an underscore \(_).| Ignore the key-value pair and continue to perform logging. | -| 2 | Invalid key type | The key must be a string. | Ignore the key-value pair and continue to perform logging. | -| 3 | Invalid value type | The supported value types vary depending on the programming language:
boolean, number, string, or Array [basic element]| Ignore the key-value pair and continue to perform logging. | -| 4 | Invalid length for values of the string type| For a value of the string type, the maximum length is 8*1024 characters. | Truncate the value with the first 8*1024 characters retained, and continue to perform logging.| -| 5 | Excess key-value pairs | The number of key-value pairs must be less than or equal to 32. | Ignore the excess key-value pairs and continue to perform logging. | -| 6 | Invalid number of elements in values of the array type | For a value of the array type, the number of elements must be less than or equal to 100. | Truncate the array with the first 100 elements retained, and continue to perform logging. | -| 7 | Invalid parameters in values of the array type | For a value of the array type, all the parameters must be of the same type, which can only be boolean, number, or string.| Ignore the key-value pair and continue to perform logging. | - -## Development Procedure +## How to Develop The following uses a one-time event watcher as an example to illustrate the development procedure. 1. Create an eTS application project. In the displayed **Project** window, choose **entry** > **src** > **main** > **ets** > **pages** > **index.ets**, and double-click **index.ets**. Then, add three buttons to simulate the process of watching for application events. Wherein, button 1 is used to invoke application event logging, button 2 to add an event watcher that automatically triggers a callback, and button 3 to remove the watcher. The complete sample code is as follows: ```ts - import hiAppEvent from '@ohos.hiAppEvent'; + import hiAppEvent from '@ohos.hiviewdfx.hiAppEvent'; @Entry @Component @@ -84,6 +58,7 @@ The following uses a one-time event watcher as an example to illustrate the deve .fontWeight(FontWeight.Bold) Button("1 writeTest").onClick(()=>{ + // Perform event logging based on the input event parameters. hiAppEvent.write({ domain: "test_domain", name: "test_event", @@ -92,14 +67,15 @@ The following uses a one-time event watcher as an example to illustrate the deve int_data: 100, str_data: "strValue" } - }).then((value) => { - console.log(`HiAppEvent success to write event: ${value}`); + }).then(() => { + console.log(`HiAppEvent success to write event`); }).catch((err) => { - console.error(`HiAppEvent failed to write event because ${err.code}`); + console.error(`code: ${err.code}, message: ${err.message}`); }); }) Button("2 addWatcherTest").onClick(()=>{ + // Add an event watcher based on the input subscription parameters. hiAppEvent.addWatcher({ name: "watcher1", appEventFilters: [{ domain: "test_domain" }], @@ -109,17 +85,23 @@ The following uses a one-time event watcher as an example to illustrate the deve timeOut: 2 }, onTrigger: function (curRow, curSize, holder) { + // If the holder object is null, return an error after recording it in the log. if (holder == null) { console.error("HiAppEvent holder is null"); return; } + // Set the size threshold to 1,000 bytes for obtaining an event package. + holder.setSize(1000); let eventPkg = null; + // Obtain the event package based on the configured size threshold. If returned event package is null, all event data has been obtained. while ((eventPkg = holder.takeNext()) != null) { - console.info("HiAppEvent eventPkg.packageId=" + eventPkg.packageId); - console.info("HiAppEvent eventPkg.row=" + eventPkg.row); - console.info("HiAppEvent eventPkg.size=" + eventPkg.size); + // Parse the obtained event package and display the result on the Log page. + console.info(`HiAppEvent eventPkg.packageId=${eventPkg.packageId}`); + console.info(`HiAppEvent eventPkg.row=${eventPkg.row}`); + console.info(`HiAppEvent eventPkg.size=${eventPkg.size}`); + // Traverse and parse event string arrays in the obtained event package. for (const eventInfo of eventPkg.data) { - console.info("HiAppEvent eventPkg.data=" + eventInfo); + console.info(`HiAppEvent eventPkg.data=${eventInfo}`); } } } @@ -127,6 +109,7 @@ The following uses a one-time event watcher as an example to illustrate the deve }) Button("3 removeWatcherTest").onClick(()=>{ + // Remove the specified event watcher. hiAppEvent.removeWatcher({ name: "watcher1" }) @@ -162,4 +145,4 @@ The following uses a one-time event watcher as an example to illustrate the deve The following sample is provided to help you better understand how to develop the application event logging feature: -- [`JsDotTest` (JS) (API8)](https://gitee.com/openharmony/applications_app_samples/tree/master/DFX/JsDotTest) +- [`JsDotTest`: Event Logging (JS) (API8)](https://gitee.com/openharmony/applications_app_samples/tree/master/DFX/JsDotTest) diff --git a/en/application-dev/dfx/hiappevent-overview.md b/en/application-dev/dfx/hiappevent-overview.md index 088f3624b0c9638dd5137e1460b3cc832c290de9..2e54f28d8a69623accc2aff1b8dc96f30045f8ed 100644 --- a/en/application-dev/dfx/hiappevent-overview.md +++ b/en/application-dev/dfx/hiappevent-overview.md @@ -1,8 +1,8 @@ # Overview of Application Event Logging -HiAppEvent provides event logging APIs for applications to log the fault, statistical, security, and user behavior events reported during running. Based on event information, you will be able to analyze the running status of your application. +The HiAppEvent module provides event logging APIs for applications to log the fault, statistical, security, and user behavior events reported during running. Based on event information, you will be able to analyze the running status of your application. -The HiAppEvent module can be used to develop application event-related functions, including flushing application events to a disk and querying historical application events. +You can use this module to develop application event-related functions, including flushing application events to a disk, querying and clearing application events, and customizing application event logging configuration. ## Basic Concepts diff --git a/en/application-dev/dfx/hitracemeter-guidelines.md b/en/application-dev/dfx/hitracemeter-guidelines.md index 316ee1b07898a24721b81625c2e9193ae08aa85f..1b45886ca4c593bbfff1b1b07d5892ad20ba58ae 100644 --- a/en/application-dev/dfx/hitracemeter-guidelines.md +++ b/en/application-dev/dfx/hitracemeter-guidelines.md @@ -12,7 +12,7 @@ The performance tracing APIs are provided by the **hiTraceMeter** module. For de | API| Return Value| Description| | ---------------------------------------------------------------------------- | --------- | ------------ | -| hiTraceMeter.startTrace(name: string, taskId: number, expectedTime?: number) | void | Starts a trace task. If multiple trace tasks with the same name need to be performed at the same time or a trace task needs to be performed multiple times concurrently, different task IDs must be specified in **startTrace**. If the trace tasks with the same name are not performed at the same time, the same task ID can be used.| +| hiTraceMeter.startTrace(name: string, taskId: number) | void | Starts a trace task. If multiple trace tasks with the same name need to be performed at the same time or a trace task needs to be performed multiple times concurrently, different task IDs must be specified in **startTrace**. If the trace tasks with the same name are not performed at the same time, the same task ID can be used.| | hiTraceMeter.finishTrace(name: string, taskId: number) | void | Stops a trace task. The values of **name** and **taskId** must be the same as those of **hiTraceMeter.startTrace**.| | hiTraceMeter.traceByValue(name: string, value: number) | void | Traces the value changes of a variable.| @@ -31,10 +31,6 @@ In this example, distributed call chain tracing begins when the application star }, onInit() { this.title = this.$t('strings.world'); - - // The expected duration of the trace task is 5 ms. - hiTraceMeter.startTrace("business", 1); - hiTraceMeter.startTrace("business", 1, 5); // Start track tasks with the same name concurrently. hiTraceMeter.startTrace("business", 1); diff --git a/en/application-dev/faqs/Readme-EN.md b/en/application-dev/faqs/Readme-EN.md index dc45ed9db0eec504b1ff6f535babf11265f2df91..0f2738b7160dcc599c54ecbe1875d279d6f3661c 100644 --- a/en/application-dev/faqs/Readme-EN.md +++ b/en/application-dev/faqs/Readme-EN.md @@ -1,19 +1,19 @@ # FAQs - [Ability Framework Development](faqs-ability.md) -- [Data Management Development](faqs-data-management.md) -- [File Management Development](faqs-file-management.md) -- [Graphics and Image Development](faqs-graphics.md) -- [hdc_std Command Usage](faqs-ide.md) -- [IDE Usage](faqs-hdc-std.md) -- [ArkUI (JavaScript) Development](faqs-ui-js.md) +- [Bundle Management Development](faqs-bundle.md) - [ArkUI (eTS) Development](faqs-ui-ets.md) +- [ArkUI (JavaScript) Development](faqs-ui-js.md) - [Graphics and Image Development](faqs-graphics.md) - [File Management Development](faqs-file-management.md) +- [Media Development](faqs-media.md) +- [Network and Connection Development](faqs-connectivity.md) - [Data Management Development](faqs-data-management.md) - [Device Management Development](faqs-device-management.md) +- [DFX Development](faqs-dfx.md) +- [Intl Development](faqs-international.md) - [Native API Usage](faqs-native.md) -- [Network and Connection Development](faqs-connectivity.md) - [Usage of Third- and Fourth-Party Libraries](faqs-third-party-library.md) -- [Development Board](faqs-development-board.md) - +- [IDE Usage](faqs-ide.md) +- [hdc_std Command Usage](faqs-hdc-std.md) +- [Development Board](faqs-development-board.md) \ No newline at end of file diff --git a/en/application-dev/faqs/faqs-ability.md b/en/application-dev/faqs/faqs-ability.md index 0cabbba71815d043e29f9c840c8ce7589af76dad..ed3cfcc4412379ea61974895ca111256b68ae696 100644 --- a/en/application-dev/faqs/faqs-ability.md +++ b/en/application-dev/faqs/faqs-ability.md @@ -4,7 +4,7 @@ Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 -A guide is available for the **DataShareExtensionAbility** class in the stage model, which provides APIs for sharing data with other applications and managing the data. +A guide is available for the **DataShareExtensionAbility** class, which provides APIs for sharing data with other applications and managing the data, in the stage model. Reference: [DataShare Development](../database/database-datashare-guidelines.md) @@ -20,6 +20,32 @@ Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 Reference: [Release Testing Version](https://gitee.com/openharmony-sig/oh-inner-release-management/blob/master/Release-Testing-Version.md) +## How do I set the UI of an ability to transparent? + +Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 + +Set the background color of the top container component to transparent, and then set the **opacity** attribute of the XComponent to **0.01**. + +Example: + +``` +build() { + Stack() { + XComponent({ + id: 'componentId', + type: 'surface', + }) + .width('100%') + .height('100%') + .opacity(0.01) + // Page content + } + .width('100%') + .height('100%') + .backgroundColor('rgba(255,255,255, 0)') +} +``` + ## How do I prevent "this" in a method from changing to "undefined" when the method is called? Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 @@ -36,7 +62,7 @@ Configure the **startWindowIcon** attribute under **abilities** in the **module. Reference: [Application Package Structure Configuration File](../quick-start/stage-structure.md) - Example: +Example: ``` { @@ -58,3 +84,133 @@ Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 Implement the **onConfigurationUpdated** callback in the **Ability** class. The callback is triggered when the system language, color mode, or display parameters (such as the orientation and density) change. Reference: [Ability Development](../ability/stage-ability.md) + +## Can I obtain the context through globalThis in the stage model? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +Do not use **globalThis** to obtain the context in the stage model. This is because all the processes of an application share a JS VM instance in the stage model. Multiple abilities can run on these processes and share the same global object. If **globalThis** is used, the context of different abilities of the same JS VM instance may be returned. + +For details about the recommended operation, see [Context in the Stage Model](../ability/context-userguide.md#context-in-the-stage-model). + +## How do I obtain the HAP file installation path of application B from application A? + +Applicable to: OpenHarmony SDK 3.0 or later, stage model of API version 9 + +First, request the system permission. For details, see [Having Your App Automatically Signed](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-auto-configuring-signature-information-0000001271659465). Then, import the **bundle** module, and call **bundle.getApplicationInfo()** to obtain application information based on the bundle name. Finally, use **application.moduleSourceDirs** to obtain the application storage path. + +## How is data returned when startAbilityForResult is called? + +Applicable to: OpenHarmony SDK3.0, stage model of API version 9 + +The callee uses **AbilityContext.terminateSelfWithResult** to destroy its ability and pass parameters to **startAbilityForResult**. For details, see [AbilityContext](../reference/apis/js-apis-ability-context.md#abilitycontextterminateselfwithresult). + +## Can the lifecycle callback of a released FA widget be triggered when the widget is displayed in the service center so that the user login information can be obtained without opening the FA application? + +Applicable to: OpenHarmony SDK 3.2.5.5, FA model of API version 8 + +After a widget is added, the **onCreate()** lifecycle is triggered so that related user information (silent login) can be displayed even when the application is not started. However, users must manually add the widget after the application is installed. + +## How do I obtain the context? + +Applicable to: OpenHarmony SDK 3.2.7.5, stage model of API version 9 + +You can use **this.context** to obtain the context in the **MainAbility.ts** file or call **getContext(this)** to obtain the context on the component page. + +## What should I do when undefined is displayed for the calling of **abilityAccessCtrl.grantUserGrantedPermission** during API version 8 syntax verification? + +Applicable to: OpenHarmony SDK 3.0, FA model of API version 8 + +**abilityAccessCtrl.grantUserGrantedPermission** is a system API. It is not available in the public SDK, which is provided as default on DevEco Studio. To use system APIs, switch to the full SDK. For details, see [Guide to Switching to Full SDK](../quick-start/full-sdk-switch-guide.md). + +## Which of the following Extension abilities are available in the public SDK: ServiceExtensionAbility, FormExtensionAbility, and DataShareExtensionAbility? + +Applicable to: OpenHarmony SDK 3.2.5.6, stage model of API version 9 + +Among the aforementioned Extension abilities, only **FormExtensionAbility** is available in the public SDK. **ServiceExtensionAbility** and **DataShareExtensionAbility** are system APIs and available only in the full SDK. + +Public SDK: intended for application developers and does not contain system APIs that require system permissions. + +Full SDK: intended for original equipment manufacturers (OEMs) and contains system APIs that require system permissions. + +## Why can't I play GIF images cyclically on the widget? + +Applicable to: OpenHarmony SDK 3.2.5.6, stage model of API version 9 + +The system does not support the display of GIF images on the widget. + +## How do I implement service login by touching a widget? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +You can start an ability upon the touch and implement service login in the ability. + +## How do I redirect to the application details page in Settings? + +Applicable to: OpenHarmony SDK 3.2.6.5 + +Refer to the following code: + +``` +this.context.startAbility( +{ + action: "action.settings.app.info", + parameters: { "settingsParamBundleName": "your app bundlename" } +}) +``` + +## How do I listen for screen rotation events? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +Refer to the following code: + +``` +let listener = mediaquery.matchMediaSync('(orientation: landscape)') +onPortrait(mediaQueryResult) { +if (mediaQueryResult.matches) { +// Do something here. + } else { +// Do something here. + } +} +listener.on('change', onPortrait) +``` + +## How do I control the shadow background size during checkbox selection? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +Set the **padding** attribute of the **\** component to control the shadow size. + +## How do I set the widget background to transparent? + +Applicable to: OpenHarmony SDK 3.2.5.5 + +1. Create the **widget/resources/styles/default.json** file in the root directory of the widget. + +2. Add the following code to the **default.json** file: + +``` +{ + "style": { + "app_background": "#00000000" + } +} +``` + +## How do I pass parameters for FA widgets? + +Applicable to: OpenHarmony SDK 3.2.5.5 + +Use **featureAbility.getWant()** and **featureAbility.getContext()** to send data through **router** in the JSON file and use **featureAbility** to receive data in the JS file. + +## How do I trigger router.disableAlertBeforeBackPage and router.enableAlertBeforeBackPage? + +Applicable to: OpenHarmony SDK 3.2.5.5 + +The following conditions must be met: + +1. Before the redirection to the previous page, a confirm dialog box will be displayed. Note that **router.disableAlertBeforeBackPage** is used to disable the display of a confirm dialog box before returning to the previous page (default), and **router.enableAlertBeforeBackPage** is used to enable the display. + +2. The system return key is used. diff --git a/en/application-dev/faqs/faqs-bundle.md b/en/application-dev/faqs/faqs-bundle.md new file mode 100644 index 0000000000000000000000000000000000000000..61a5277c6d4a1493d0281fdd66b88a99a07141ae --- /dev/null +++ b/en/application-dev/faqs/faqs-bundle.md @@ -0,0 +1,31 @@ +# Bundle Management Development + +## How do I obtain the version code and version name of an application? + +Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 + +Use **bundle.getBundleInfo()** to obtain the bundle information, which contains the version code and version name. + +Reference: [Bundle](../reference/apis/js-apis-Bundle.md#bundlegetbundleinfo) + +## How do I obtain the bundle name of an application? + +Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 + +Obtain the bundle name through **context.abilityInfo.bundleName**. + +Reference: [AbilityContext](../reference/apis/js-apis-ability-context.md) and [AbilityInfo](../reference/apis/js-apis-bundle-AbilityInfo.md) + +## How do I obtain an application icon? + +Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 + +Use **bundle.getAbilityIcon** to obtain the application icon. To use this API, you must configure the permission **ohos.permission.GET_BUNDLE_INFO**. + +Reference: [Bundle](../reference/apis/js-apis-Bundle.md#bundlegetbundleinfo) + +## How do I determine whether an application is a system application? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +Use **bundle.getApplicationInfo** to obtain the application information, and then check the value of **systemApp** in the information. The application is a system application if the value is **true**. diff --git a/en/application-dev/faqs/faqs-connectivity.md b/en/application-dev/faqs/faqs-connectivity.md index 3b8dea82129c03f0dc12c12296a28b9a0c46c99b..31e1db2e15e82875427d52a92dd26bcfeb69c34e 100644 --- a/en/application-dev/faqs/faqs-connectivity.md +++ b/en/application-dev/faqs/faqs-connectivity.md @@ -19,9 +19,9 @@ Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 -Error code 28 refers to **CURLE_OPERATION_TIMEDOUT**, which means a libcurl library operation timeout. For details, see any HTTP status code description available. +Error code 28 refers to **CURLE_OPERATION_TIMEDOUT**, which means a cURL operation timeout. For details, see any HTTP status code description available. -Reference: [Development Guide](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-http.md#httpresponse) and [Curl Error Codes](https://curl.se/libcurl/c/libcurl-errors.html) +Reference: [Response Codes](../reference/apis/js-apis-http.md#responsecode) and [Curl Error Codes](https://curl.se/libcurl/c/libcurl-errors.html) ## What does error code 6 mean for the response of \@ohos.net.http.d.ts? @@ -30,4 +30,4 @@ Applicable to: OpenHarmony SDK 3.2.3.5 Error code 6 indicates a failure to resolve the host in the address. You can ping the URL carried in the request to check whether the host is accessible. -Reference: [Development Guide](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-http.md#httpresponse) and [Curl Error Codes](https://curl.se/libcurl/c/libcurl-errors.html) +Reference: [Response Codes](../reference/apis/js-apis-http.md#responsecode) and [Curl Error Codes](https://curl.se/libcurl/c/libcurl-errors.html) diff --git a/en/application-dev/faqs/faqs-data-management.md b/en/application-dev/faqs/faqs-data-management.md index 839514879b8198273bc86680614b6b2054f662e2..47f0b7ce20cd54a1cee4eb521801d4e7ca94e04b 100644 --- a/en/application-dev/faqs/faqs-data-management.md +++ b/en/application-dev/faqs/faqs-data-management.md @@ -1,12 +1,10 @@ -# Device Management Development +# Data Management Development - - -## How Do I Save PixelMap data to a database? +## How Do I Save PixelMap Data to a Database? Applicable to: OpenHarmony SDK 3.2.3.5 -You can convert a **PixelMap** into a **ArrayBuffer** and save the **ArrayBuffer** to your database. +You can convert a **PixelMap** into an **ArrayBuffer** and save the **ArrayBuffer** to your database. Reference: [readPixelsToBuffer](../reference/apis/js-apis-image.md#readpixelstobuffer7-1) @@ -14,11 +12,65 @@ Reference: [readPixelsToBuffer](../reference/apis/js-apis-image.md#readpixelstob Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 -Run the hdc_std command to copy the .db, .db-shm, and .db-wal files from **/data/app/el2/100/database/Bundle name/entry/db/**, and then use the SQLite tool to open the files. +Run the hdc_std command to copy the .db, .db-shm, and .db-wal files in **/data/app/el2/100/database/*bundleName*/entry/db/**, and then use the SQLite tool to open the files. Example: - ``` hdc_std file recv /data/app/el2/100/database/com.xxxx.xxxx/entry/db/test.db ./test.db ``` + +## Does the Database Has a Lock Mechanism? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +The distributed data service (DDS), relational database (RDB) store, and preferences provided OpenHarmony have a lock mechanism. You do not need to bother with the lock mechanism during the development. + +## What Is a Transaction in an RDB Store? + +Applicable to: all versions + +When a large number of operations are performed in an RDB store, an unexpected exception may cause a failure of some data operations and loss of certain data. As a result, the application may become abnormal or even crash. + +A transaction is a group of tasks serving as a single logical unit. It eliminates the failure of some of the operations and loss of associated data. + +## What Data Types Does an RDB Store Support? + +Applicable to: OpenHarmony SDK 3.0 or later, stage model of API version 9 + +An RDB store supports data of the number, string, and Boolean types. The number array supports data of the Double, Long, Float, Int, or Int64 type, with a maximum precision of 17 decimal digits. + +## How Do I View Database db Files? + +Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 + +1. Run the **hdc_std shell** command. + +2. Obtain the absolute path or sandbox path of the database. + +The absolute path is **/data/app/el2//database/**. The default **** is **100**. + +To obtain the sandbox path, run the **ps -ef | grep hapName** command to obtain the process ID of the application. + +The database sandbox path is **/proc//root/data/storage/el2/database/**. + +3. Run the **find ./ -name "\*.db"** command in the absolute path or sandbox path of the database. + +## How Do I Store Long Text Data? + +Applicable to: OpenHarmony SDK 3.2.5.5, API version 9 + +- Preferences support a string of up to 8192 bytes. + +- The KV store supports a value of up to 4 MB. + +Reference: [Preference Overview](../database/database-preference-overview.md) and [Distributed Data Service Overview](../database/database-mdds-overview.md) + +## How Do I Develop DataShare on the Stage Model + +Applicable to: OpenHarmony SDK 3.2.5.5, API version 9 + +The DataShare on the stage model cannot be used with the **DataAbility** for the FA model. The connected server application must be implemented by using **DataShareExtensionAbility**. + +Reference: [DataShare Development](../database/database-datashare-guidelines.md) + diff --git a/en/application-dev/faqs/faqs-development-board.md b/en/application-dev/faqs/faqs-development-board.md index 4766d4f5271dec2e5ec937477cf1ce1b7946eef6..79e5fc390f934f82eb3d70468f9ed41faed68947 100644 --- a/en/application-dev/faqs/faqs-development-board.md +++ b/en/application-dev/faqs/faqs-development-board.md @@ -1,6 +1,4 @@ -# Development Board - - +# Development Board Usage ## How do I take screenshots on a development board? @@ -29,8 +27,8 @@ Applicable to: DevEco Studio 3.0.0.991 1. Create a profile in Previewer. ![en-us_image_0000001361254285](figures/en-us_image_0000001361254285.png) -2. Set the profile parameters as follows: +2. Set the profile parameters as follows: Device type : default Resolution: 720\*1280 diff --git a/en/application-dev/faqs/faqs-device-management.md b/en/application-dev/faqs/faqs-device-management.md index 5bb748f758a4636fb40ae5d7fb741eccfb5306fe..dd836eb11abfbee3979f5a604eb5aa734d0d9112 100644 --- a/en/application-dev/faqs/faqs-device-management.md +++ b/en/application-dev/faqs/faqs-device-management.md @@ -1,12 +1,10 @@ # Device Management Development - - ## How do I obtain the DPI of a device? Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 -Import the **@ohos.display** module and call the **getDefaultDisplay** API. +Import the **\@ohos.display** module and call the **getDefaultDisplay** API. Example: @@ -20,5 +18,33 @@ display.getDefaultDisplay((err, data) => { } console.info('Test Succeeded in obtaining the default display object. Data:' + JSON.stringify(data)); console.info('Test densityDPI:' + JSON.stringify(data.densityDPI)); -});https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-device-info.md) +}); ``` + +## How do I obtain the type of the device where the application is running? + +Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 + +Import the **\@ohos.deviceInfo** module and call the **deviceInfo.deviceType** API. + +For details, see [Device Information](../reference/apis/js-apis-device-info.md). + +## How do I obtain the system version of a device? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +Use the **osFullName** attribute of the [deviceInfo](../reference/apis/js-apis-device-info.md) object. + +## How do I obtain the UDID of an OpenHarmony device? + +Applicable to: OpenHarmony SDK3.0, stage model of API version 9 + +- To obtain the UDID of the connected device, run the **hdc shell bm get --udid** command. + +- For details about how to obtain the UDID from code, see [udid](../reference/apis/js-apis-device-info.md). + +## How do I develop a shortcut key function? + +Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 + +To develop a shortcut key function, use the APIs in [Input Consumer](../reference/apis/js-apis-inputconsumer.md). diff --git a/en/application-dev/faqs/faqs-dfx.md b/en/application-dev/faqs/faqs-dfx.md new file mode 100644 index 0000000000000000000000000000000000000000..ec1c8dbfedd5fa3c087c96d54c9c2aab73d75e8a --- /dev/null +++ b/en/application-dev/faqs/faqs-dfx.md @@ -0,0 +1,54 @@ +# DFX Development + +## How do I locate the fault when the application crashes? + +Applicable to: OpenHarmony SDK 3.2.5.5 + +1. Locate the crash-related code based on the service log. + +2. View the error information in the crash file. The crash file is located at **/data/log/faultlog/faultlogger/**. + +## Why cannot access controls in the UiTest test framework? + +Applicable to: OpenHarmony SDK 3.2.5.5 + +Check whether **persist.ace.testmode.enabled** is turned on. + +Run **hdc\_std shell param get persist.ace.testmode.enabled**. + +If the value is **0**, run the **hdc\_std shell param set persist.ace.testmode.enabled 1** to enable the test mode. + + +## Why is private displayed in logs when the format parameter type of HiLog in C++ code is %d or %s? + +When format parameters such as **%d** and **%s** are directly used, the standard system uses **private** to replace the actual data for printing by default to prevent data leakage. To print the actual data, replace **%d** with **%{public}d** or replace **%s** with **%{public}s**. + +## What should I do if the hilog.debug log cannot be printed? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +Run **hdc_std shell hilog -b D** to turn on the debugging switch. + +## Is HiLog or console recommended for log printing? How do I set the domain if HiLog is used? + +Applicable to: OpenHarmony SDK 3.2.2.5 + +You are advised to use the [HiLog](../reference/apis/js-apis-hilog.md) for log printing. For details about how to set the **domain** parameter, see the [Development Guide](../reference/apis/js-apis-hilog.md#hilogisloggable). + +## What is the maximum length of a log record when HiLog is used? Is it configurable? + +Applicable to: OpenHarmony SDK 3.2.2.5 + +The maximum length of a log record is 1,024 characters, and it is not changeable. + +## Can I separate multiple strings by spaces in the tag parameter of the HiLog API? + +Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 + +No. Separating multiple strings by spaces is not allowed. + +## How do I print real data if HiLog does not contain data labeled by {public}? + +Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 + +Run **hdc\_std shell hilog -p off** to disable logging of data labeled by {public}. diff --git a/en/application-dev/faqs/faqs-file-management.md b/en/application-dev/faqs/faqs-file-management.md index 1e3740047768d5d5fefa1420659c64da403ad587..adac2f5a6739a85c04005ef8068369776e90581c 100644 --- a/en/application-dev/faqs/faqs-file-management.md +++ b/en/application-dev/faqs/faqs-file-management.md @@ -1,15 +1,65 @@ # File Management Development +## Does fileio.rmdir Delete Files Recursively? +Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 -## What If There is No Return Value or Error Captured After getAlbums Is Called? +Yes. **fileio.rmdir** deletes files recursively. + +## How Do I Create a File That Does Not Exist? + +Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 + +You can use **fileio.open(filePath, 0o100, 0o666)**. The second parameter **0o100** means to create a file if it does not exist. The third parameter **mode** must also be specified. + +## What If "call fail callback fail, code: 202, data: json arguments illegal" Is Displayed? + +Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 + +When the **fileio** module is used to copy files, the file path cannot start with "file:///". + +## How Do I Read Files Outside the App Sandbox? + +Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 + +If the input parameter of the **fileio** API is **path**, only the sandbox directory of the current app obtained from the context can be accessed. To access data in other directories such as the user data, images, and videos, open the file as the data owner and operate with the file descriptor (FD) returned. + +For example, to read or write a file in Media Library, perform the following steps: + +1. Use **getFileAssets()** to obtain the **fileAsset** object. + +2. Use **fileAsset.open()** to obtain the FD. + +3. Use the obtained FD as the **fileIo** API parameter to read and write the file. + +## What If the File Contains Garbled Characters? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +Read the file content from the buffer, and decode the file content using **util.TextDecoder**. + +Example: + +``` +import util from '@ohos.util' +async function readFile(path) { + let stream = fileio.createStreamSync(path, "r+"); + let readOut = await stream.read(new ArrayBuffer(4096)); + let textDecoder = new util.TextDecoder("utf-8", { ignoreBOM: true }); + let buffer = new Uint8Array(readOut.buffer) + let readString = textDecoder.decode(buffer, { stream: false }); + console.log ("[Demo] File content read: "+ readString); +} +``` + +## What Should I Do If There Is No Return Value or Error Captured After getAlbums Is Called? Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 -The **ohos.permission.READ_MEDIA** permission is required for calling **getAlbums**, and this permission needs user authorization. For details, see OpenHarmony [Application Permission List](../security/permission-list.md). +The **ohos.permission.READ_MEDIA** is required for using **getAlbums()**. In addition, this permission needs user authorization. For details, see [OpenHarmony Permission List](../security/permission-list.md). 1. Configure the required permission in the **module.json5** file. - + ``` "requestPermissions": [ { @@ -19,7 +69,7 @@ The **ohos.permission.READ_MEDIA** permission is required for calling **getAlbum ``` 2. Add the code for user authorization before the **MainAbility.ts -> onWindowStageCreate** page is loaded. - + ``` private requestPermissions() { let permissionList: Array = [ @@ -34,3 +84,21 @@ The **ohos.permission.READ_MEDIA** permission is required for calling **getAlbum }) } ``` + +## What Do I Do If the App Crashes When FetchFileResult() Is Called Multiple Times? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +Each time after the **FetchFileResult** object is called, call **FetchFileResult.close()** to release and invalidate the **FetchFileResult** object . + +## What If An Error Is Reported by IDE When mediaLibrary.getMediaLibrary() Is Called in the Stage Model? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +In the stage model, use **mediaLibrary.getMediaLibrary(context: Context)** to obtain the media library instance. + +## How Do I Sort the Data Returned by mediaLibrary.getFileAssets()? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +Use the **order** attribute in **[MediaFetchOptions](../reference/apis/js-apis-medialibrary.md#mediafetchoptions7)** to sort the data returned. diff --git a/en/application-dev/faqs/faqs-graphics.md b/en/application-dev/faqs/faqs-graphics.md index c4e151559b547b2cdb4f8d7cb19b35318203674a..7752d9d746fc3cfe3d8b7028ada2c4d3c5af2136 100644 --- a/en/application-dev/faqs/faqs-graphics.md +++ b/en/application-dev/faqs/faqs-graphics.md @@ -11,3 +11,80 @@ In effect, the **isStatusBarLightIcon** and **isNavigationBarLightIcon** attribu Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 Import the **\@ohos.window** module, and call **window.setSystemBarProperties()**. + +## How do I hide the status bar to get the immersive effect? + +Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 + +1. Use the **onWindowStageCreate** to obtain a **windowClass** object. + + ``` + onWindowStageCreate(windowStage) { + // When the main window is created, set the main page for this ability. + console.log("[Demo] MainAbility onWindowStageCreate") + windowStage.getMainWindow((err, data) => { + if (err.code) { + console.error('Failed to obtain the main window.') + return; + } + // Obtain a windowClass object. + globalThis.windowClass = data; + }) + } + ``` + +2. Enable the full-screen mode for the window and hide the status bar. + + ``` + globalThis.windowClass.setFullScreen(isFullScreen, (err, data) => { + if (err.code) { + console.error('Failed to enable the full-screen mode. Cause:' + JSON.stringify(err)); + return; + } + console.info('Succeeded in enabling the full-screen mode. Data: ' + JSON.stringify(data)); + }); + ``` + +## How do I obtain the window width and height? + +Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 + +Use **window.getProperties()** to obtain the window properties. The **windowRect** field in the properties specifies the window width and height. + +Example: + + +``` +let promise = windowClass.getProperties(); +promise.then((data)=> { + console.info('Succeeded in obtaining the window properties. Data: ' + JSON.stringify(data.windowRect)); +}).catch((err)=>{ + console.error('Failed to obtain the window properties. Cause: ' + JSON.stringify(err)); +}); +``` + +## How do I set the color of the system bar? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +Refer to the following code: + + +``` +window.getTopWindow(globalThis.mainContext).then(win => { + var systemBarProperties = { + statusBarColor: '#19B6FF', // Set the background color of the status bar. + navigationBarColor: '#19B6FF', // Set the background color of the navigation bar. + isStatusBarLightIcon: false, // Set the icon on the status bar not to be highlighted. + isNavigationBarLightIcon: true, // Set the icon on the navigation bar to be highlighted. + statusBarContentColor: '#0D0500', // Set the text color of the status bar. + navigationBarContentColor: '#FFA500' // Set the text color of the navigation bar. + }; + win.setSystemBarProperties(systemBarProperties).catch(err => { + INDEX_LOGGER.info(`set System Bar Properties failed:${err}`) + }) +}) +.catch(err => { + INDEX_LOGGER.info(`get top window failed:${err}`) +}) +``` diff --git a/en/application-dev/faqs/faqs-hdc-std.md b/en/application-dev/faqs/faqs-hdc-std.md index 04c0a202a57b702164b8bcb7a32299d3abd5d75c..60f93da61d7d78a4e148b65c0e30d379b1e1206d 100644 --- a/en/application-dev/faqs/faqs-hdc-std.md +++ b/en/application-dev/faqs/faqs-hdc-std.md @@ -1,17 +1,14 @@ # hdc_std Command Usage - - -## What are the commands commonly used for log management? +## Common Log Commands Applicable to: OpenHarmony SDK 3.2.2.5 -- Clearing logs: hdc_std shell hilog -r +Clearing logs: hdc_std shell hilog -r -- Increasing the buffer size to 20 MB: hdc_std shell hilog -G 20M - -- Capturing logs: hdc_std shell hilog > log.txt +Increasing the buffer size to 20 MB: hdc_std shell hilog -G 20M +Capturing logs: hdc_std shell hilog > log.txt ## What should I do to avoid log flow control? @@ -27,43 +24,64 @@ Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 After performing the preceding operations, restart the DevEco Studio. +## What should I do if the HAP installed on the development board through the IDE cannot be opened? -## Is HiLog or Console recommended for log printing? How do I set the domain if HiLog is used? +Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 -Applicable to: OpenHarmony SDK 3.2.2.5 +Check whether the SDK version is consistent with the system version on the development board. You are advised to use the SDK version and system version that are released on the same day. -[HiLog](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-hilog.md) is recommended for an application to print logs. For details about domain setting, see [Development Guide](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-hilog.md#hilogisloggable). +## How do I upload files using the hdc command? +Applicable to: OpenHarmony SDK 3.2.2.5 -## What is the maximum length of a log record when HiLog is used? Is it configurable? +Run the **hdc_std file send** command. -Applicable to: OpenHarmony SDK 3.2.2.5 +## How do I prevent the screen of the RK3568 development board from turning off? -The maximum length of a log record is 1,024 characters, and it is not changeable. +Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 +Run the **hdc_std shell "power-shell setmode 602"** command. -## What should I do if a HAP package cannot be opened after being installed on the development board using the IDE? +## How do I start an ability using the hdc command? Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 -Check whether the SDK version is consistent with the system version on the development board. You are advised to use the SDK version and system version that are released on the same day. +Run the **hdc\_std shell aa start -a AbilityName -b bundleName -m moduleName** command. +## How do I change the read and write permissions on a file directory on the development board? -## How do I upload files using an hdc command? +Applicable to: OpenHarmony SDK 3.2.5.6, stage model of API version 9 + +Run the **hdc\_std shell mount -o remount,rw /** command. + +## What should I do if the error message "Unknown file option -r" is displayed when hdc_std file recv is run? + +Applicable to: OpenHarmony SDK 3.2.5.6, stage model of API version 9 + +1. Use the the hdc tool in the device image or SDK of the same version. + +2. Remove any Chinese characters or spaces from the directory specified for the hdc tool. + +## How do I uninstall an application using the hdc command? Applicable to: OpenHarmony SDK 3.2.2.5 -Run the **hdc_std file send** command. +Run the **hdc\_std uninstall [-k] [package_name]** command. -## How do I prevent the screen of the RK3568 development board from turning off? +## How do I check whether the system is 32-bit or 64-bit? -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 +Applicable to: OpenHarmony SDK 3.2.5.5 -Run the **hdc_std shell "power-shell setmode 602"** command. +Run the **hdc\_std shell getconf LONG_BIT** command. +If **64** is returned, the system is a 64-bit one. Otherwise, the system is a 32-bit one. -## How do I start an ability using an hdc command? +## How do I view the component tree structure? -Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 +Applicable to: OpenHarmony SDK 3.2.5.5 + +1. Run the **hdc\_std shell** command to launch the CLI. + +2. Run the **aa dump -a** command to find **abilityID**. -Run the **hdc_std shell aa start -a AbilityName -b bundleName -m moduleName** command. +3. Run the **aa dump -i [abilityID] -c -render** command to view the component tree. diff --git a/en/application-dev/faqs/faqs-international.md b/en/application-dev/faqs/faqs-international.md new file mode 100644 index 0000000000000000000000000000000000000000..546402921ce3a2cd9f9972721727a84d9a31295a --- /dev/null +++ b/en/application-dev/faqs/faqs-international.md @@ -0,0 +1,19 @@ +# Intl Development + +## How resources in AppScope, such as images and text, are referenced? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +Resources are referenced in the **$r('app.type.name')** format. Where, **type** indicates the resource type, such as color, string, and media, and **name** indicates the resource name. + +## How do I convert the resource type to string? + +Applicable to: OpenHarmony SDK3.0, stage model of API version 9 + +If the resource type is set to **string**, the qualifier directory can be set as **this.context.resourceManager.getStringSync(\\$r('app.string.test').id)** and can be converted synchronously. The **\$r('app.string.test', 2)** mode is not supported. For more usage methods, see [Resource Manager](../reference/apis/js-apis-resource-manager.md#getstringsync9). + +## Why should I do if the constants referenced by $ in the form_config.json file does not take effect? + +Applicable to: OpenHarmony SDK 3.2.6.5, API9 Stage model + +In the **form\_config.json** file, **$** cannot be used to reference constants. diff --git a/en/application-dev/faqs/faqs-media.md b/en/application-dev/faqs/faqs-media.md new file mode 100644 index 0000000000000000000000000000000000000000..9f465834a0951246f822ef2b5f8a5bf619ec1c5a --- /dev/null +++ b/en/application-dev/faqs/faqs-media.md @@ -0,0 +1,128 @@ +# Media Development + +## How do I set a front camera? + +Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 + +1. Set the camera position to **camera.CameraPosition.CAMERA_POSITION_FRONT**. + +2. Create a **CameraInput** instance based on the camera position and type. + +Reference: [Camera Management](../reference/apis/js-apis-camera.md) + +Example: + +``` +// The rear camera is set by default. You can use **isFrontCamera** to switch to the rear camera. +let cameraId +let cameraInput +for(let cameraIndex = 0; cameraIndex < this.cameraArray.length; cameraIndex++) { + let faceType = this.cameraArray[cameraIndex].cameraPosition + switch(faceType) { + case camera.CameraPosition.CAMERA_POSITION_FRONT: // Front camera + if(this.isFrontCamera){ + cameraId = this.cameraArray[cameraIndex].cameraId + } + break + case camera.CameraPosition.CAMERA_POSITION_BACK: // Rear camera + if(!this.isFrontCamera){ + cameraId = this.cameraArray[cameraIndex].cameraId + } + break + case camera.CameraPosition.CAMERA_POSITION_UNSPECIFIED: + default: + break + } +} +cameraInput = await this.cameraManager.createCameraInput(cameraId) +``` + +## How do I crop an image? + +Applicable to: OpenHarmony SDK 3.2.5.6, stage model of API version 9 + +1. Create an **ImageSource** instance based on the input URI. + + ``` + let path = this.context.getApplicationContext().fileDirs + "test.jpg"; + const imageSourceApi = image.createImageSource(path); + ``` + +2. Set decoding parameters and decode the image to obtain a **PixelMap** object. Image processing is supported during decoding. + - Set **desiredSize** to specify the target size after scaling. If the values are all set to **0**, scaling will not be performed. + - Set **desiredRegion** to specify the target rectangular area after cropping. If the values are all set to **0**, cropping will not be performed. + - Set **rotateDegrees** to specify the rotation angle. The image will be rotated clockwise at the center. + + ``` + const decodingOptions = { + desiredSize: { + height:0, + width:0 + }, + // Crop a rectangular area. + desiredRegion: { + size: { + height:100, + width:100 + }, + x:0, + y:0 + }, + // Rotate the image by 90 degrees. + rotate:90 + } + imageSourceApi.createPixelMap(decodingOptions).then(pixelMap => { + this.handlePixelMap(pixelMap) + }) + ``` + +3. Process the obtained **PixelMap** object. For example, render and display the image. + +## How do I apply for the media read/write permission on a device? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 + +1. Configure the permissions **ohos.permission.READ_MEDIA** and **ohos.permission.WRITE_MEDIA** in the **module.json5** file. + Example: + + + ``` + { + "module" : { + "requestPermissions":[ + { + "name" : "ohos.permission.READ_MEDIA", + "reason": "$string:reason" + }, + { + "name" : "ohos.permission.WRITE_MEDIA", + "reason": "$string:reason" + } + ] + } + } + ``` + +2. Call **requestPermissionsFromUser** to request the permissions from end users in the form of a dialog box. This operation is required because the grant mode of both permissions is **user_grant**. + + ``` + let permissions: Array = ['ohos.permission.READ_MEDIA','ohos.permission.WRITE_MEDIA'] + context.requestPermissionsFromUser(permissions).then((data) => { + console.log("Succeed to request permission from user with data: " + JSON.stringify(data)) + }).catch((error) => { + console.log("Failed to request permission from user with error: " + JSON.stringify(error)) + }) + ``` + +## Why can't I play MP4 videos? + +Applicable to: OpenHarmony SDK 3.2.7.5, stage model of API version 9 + +Currently, the system does not support the playback of MP4 videos in H.265 format. + + +## Why can't I play a new video or even encounters a crash after creating more than 10 videos? + +Applicable to: OpenHarmony SDK 3.2.7.5, stage model of API version 9 + +A maximum of 13 media player instances can be created. diff --git a/en/application-dev/faqs/faqs-native.md b/en/application-dev/faqs/faqs-native.md index da00895e4a5b5a532e67f9f709dd84c25abe3205..ef5700bb0ec1e3c903fd758d644779856f0ce681 100644 --- a/en/application-dev/faqs/faqs-native.md +++ b/en/application-dev/faqs/faqs-native.md @@ -1,12 +1,30 @@ # Native API Usage +## Is there a native API that provides functions similar to Canvas? + +Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 + +Yes. The native API **Drawing** provides similar functions. It can be used for 2D drawing. + ## When a native HAP is running, the error message "Obj is not a valid object" is displayed for the imported namespace. What should I do? Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 Check the **abiFilters** parameter value in the **build-profile.json5** file in the root directory of the module (not the root directory of the project). If the device is 32-bit, the value must be **armeabi-v7a**. If the device is 64-bit, the value must be **arm64-v8a**. -## How do I obtain the value of version in the package.json file of a module in the C++ code developed using native APIs? +## What should I do when the error message "install parse profile prop check error" is displayed during the running of a native HAP? + +Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 + +Check the **abiFilters** parameter value in the **build-profile.json5** file in the root directory of the module (not the root directory of the project). If the device is 32-bit, the value must be **armeabi-v7a**. If the device is 64-bit, the value must be **arm64-v8a**. + +## What should I do when the error message "undefined symbol: OH_LOG_Print" is displayed during log printing by **OH_LOG_Print**? + +Applicable to: OpenHarmony SDK 3.2.6.3, stage model of API version 9 + +Modify the **CMakeLists.txt** file by adding **libhilog_ndk.z.so** to the end of **target_link_libraries**. + +## How do I obtain the value of version in the package.json file of a module? Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 @@ -53,3 +71,9 @@ static napi_value Add(napi_env env, napi_callback_info info) return fixed_version_value; } ``` + +## How do I traverse files in rawfile? + +Applicable to: OpenHarmony SDK 3.2 or later, stage model of API version 9 + +Use the native API **OH_ResourceManager_OpenRawDir()** to obtain the root directory of **rawfile** and traverse the root directory. diff --git a/en/application-dev/faqs/faqs-third-party-library.md b/en/application-dev/faqs/faqs-third-party-library.md index 323269c5e0a4d8c84e9adbb39c4184bba9a00b5e..898055cd200805d8df549b33bb2c5f3b4b05bca6 100644 --- a/en/application-dev/faqs/faqs-third-party-library.md +++ b/en/application-dev/faqs/faqs-third-party-library.md @@ -1,7 +1,74 @@ # Usage of Third- and Fourth-Party Libraries -## What does the following error message mean : "Stage model module... does not support including OpenHarmony npm packages or modules in FA model. OpenHarmony build tasks will not be executed, and OpenHarmony resources will not be packed." +## What does the following error message mean: "Stage model module... does not support including OpenHarmony npm packages or modules in FA model. OpenHarmony build tasks will not be executed, and OpenHarmony resources will not be packed." Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 The third- and fourth-party libraries are not yet compatible with the stage model of API version 9 and cannot be used. + +## Can I transfer project-level dependencies? + +Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 + +For example, if project A depends on project B and project B depends on project C, can project A directly use the APIs provided by project C? + +No. Project A cannot directly use the APIs provided by project C. The project packing tool NPM does not support dependency transfer. To use the APIs provided by project C, you can add the dependency of project C to project A. + +## How do I obtain available third-party libraries? + +Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 + +For details, see [Third-Party Components That Can Be Directly Used on OpenHarmony](https://gitee.com/openharmony-sig/third_party_app_libs). + +## Which third-party libraries are related to network requests? + +Applicable to: OpenHarmony SDK 3.2.6.5, stage model of API version 9 + +The [Axios](https://gitee.com/openharmony-sig/axios) library is related to network requests. + +## How do I use NPM to import third- and fourth-party libraries? + +Applicable to: OpenHarmony SDK 3.2.5.5, stage model of API version 9 +- Method 1: + 1. Open the **Terminal** window and run the following command to go to the **entry** directory: + + ``` + cd entry + ``` + 2. Run the following command to install a third-party package, for example, **dayjs**: + + ``` + npm install dayjs --save + ``` + 3. Add the following statement in the .js file to import the package: + + ``` + import dayjs from 'dayjs'; + ``` + +- Method 2: + 1. Enter the **entry** directory of the project and open the **package.json** file. + 2. Write the third-party NPM package to be installed (for example, **dayjs**) in the **package.json** file. + + ``` + { + "dependencies": { + "dayjs": "^1.10.4", + } + } + ``` + 3. Open the **Terminal** window and run the following command to go to the **entry** directory: + + ``` + cd entry + ``` + 4. Run the following command to install NPM: + + ``` + npm install + ``` + 5. Add the following statement in the .js file to import the package: + + ``` + import dayjs from 'dayjs'; + ``` diff --git a/en/application-dev/faqs/faqs-ui-ets.md b/en/application-dev/faqs/faqs-ui-ets.md index fd21421cd95edc2bc838b8401724fae10448d9fd..3ec2b755e3e99db07930d5f8a6d01975985f4948 100644 --- a/en/application-dev/faqs/faqs-ui-ets.md +++ b/en/application-dev/faqs/faqs-ui-ets.md @@ -1,4 +1,4 @@ -# ArkUI (eTS) Development +# ArkUI (ArkTS) Development @@ -72,7 +72,7 @@ Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 2. Convert data in Uint8Array format to the string type by calling the **String.fromCharCode** API. -Reference: [Resource Management](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-resource-manager.md) +Reference: [Resource Management](../reference/apis/js-apis-resource-manager.md) Example: @@ -94,7 +94,7 @@ Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 Use the **resourceManager.getString()** API of the **\@ohos.resourceManager** module. -Reference: [Resource Management](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-resource-manager.md#getstring) +Reference: [Resource Management](../reference/apis/js-apis-resource-manager.md#getstring) ## What should I do if the global static variables of a class do not work? @@ -102,8 +102,6 @@ Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 Objects imported to abilities and pages are packaged into two different closures, that is, two global objects. In this case, a static variable referenced by the abilities is not the same object as that referenced by the pages. Therefore, global variables cannot be defined by defining static variables in the class. You are advised to use AppStorage to manage global variables. -Reference: [AppStorage](https://docs.openharmony.cn/pages/v3.2Beta/en/application-dev/ui/ts-application-states-appstorage.md/) - ## How do I obtain resources in the stage model? Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 @@ -154,9 +152,9 @@ build() { Applicable to: OpenHarmony SDK 3.2.2.5, stage model of API version 9 -No. Currently, **CustomDialog** can be used only on eTS pages. +No. Currently, **CustomDialog** can be used only on ArkTS pages. -Reference: [Custom Dialog Box](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/arkui-ts/ts-methods-custom-dialog-box.md) +Reference: [Custom Dialog Box](../reference/arkui-ts/ts-methods-custom-dialog-box.md) ## How do I transfer variables in CustomDialog to variables on pages? @@ -202,7 +200,7 @@ struct DialogTest { Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 -The **\** component is a scrollable container. By default, it taks up the entire screen height. When any component with a fixed height takes up part of the screen height, you need to explicitly specify **layoutWeight(1)** for the parent container of the **\** component to take up the remaining height instead of the entire screen height. +The **\** component is a scrollable container. By default, it takes up the entire screen height. When any component with a fixed height takes up part of the screen height, you need to explicitly specify **layoutWeight(1)** for the parent container of the **\** component to take up the remaining height instead of the entire screen height. ## How do I center child components in a grid container? @@ -210,7 +208,7 @@ Applicable to: OpenHarmony SDK 3.2.5.3, stage model of API version 9 By default, child components in a **\** are horizontally aligned to the left. To center them, perform the following steps: -Nest a **\** component and set it to **justifyContent(FlexAlign.Center)**. For details, see [Grid Layout](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ui-ts-layout-grid-container.md). +Nest a **\** component and set it to **justifyContent(FlexAlign.Center)**. For details, see [Grid Layout](../reference/arkui-ts/ts-container-gridcontainer.md). Example: @@ -267,13 +265,13 @@ export default class MainAbility extends Ability { } ``` -## How do I execute JavaScript functions in the \ component in eTS code? +## How do I execute JavaScript functions in the \ component in ArkTS code? Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 Call the **runJavaScript** API in the **WebController** to asynchronously execute JavaScript scripts. This API uses a callback to return the execution result. Note: **runJavaScript** can only be called after **loadUrl** has been completed. For example, it can be called in **onPageEnd**. -Reference: [Web](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/arkui-ts/ts-basic-components-web.md) +Reference: [Web](../reference/arkui-ts/ts-basic-components-web.md) ## How do I fix misidentification of the pan gesture where container nesting is involved? diff --git a/en/application-dev/faqs/faqs-ui-js.md b/en/application-dev/faqs/faqs-ui-js.md index 5d39db33199fddf298e66e4bd290999b58d6dddb..c60ff729eae773a356a50da1b9197c1de2b9c120 100644 --- a/en/application-dev/faqs/faqs-ui-js.md +++ b/en/application-dev/faqs/faqs-ui-js.md @@ -1,7 +1,5 @@ # ArkUI (JavaScript) Development - - ## How do I convert the fields in an XML file into JavaScript objects? Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 @@ -13,38 +11,37 @@ Example: ``` import convertxml from '@ohos.convertxml'; -// Code snippet -xml = +// XML strings +let xml = '' + '' + ' Happy' + ' Work' + ' Play' + ''; -let conv = new convertxml.ConvertXML(); +let conv = new convertxml.ConvertXML(); // Options for conversion. For details, see the reference document. -let options = {trim : false, declarationKey:"_declaration", - instructionKey : "_instruction", attributesKey : "_attributes", - textKey : "_text", cdataKey:"_cdata", doctypeKey : "_doctype", - commentKey : "_comment", parentKey : "_parent", typeKey : "_type", - nameKey : "_name", elementsKey : "_elements"} -let result:any = conv.convert(xml, options) // Convert fields in the XML file into JavaScript objects. +let options = { + trim: false, + declarationKey: "_declaration", + instructionKey: "_instruction", + attributesKey: "_attributes", + textKey: "_text", + cdataKey: "_cdata", + doctypeKey: "_doctype", + commentKey: "_comment", + parentKey: "_parent", + typeKey: "_type", + nameKey: "_name", + elementsKey: "_elements" +} +let result: any = conv.convert(xml, options) // Convert fields in the XML file into JavaScript objects. console.log('Test: ' + JSON.stringify(result)) -console.log('Test: ' + result._declaration._attributes.version) // vesion field in XML file -console.log('Test: ' + result._elements[0]._elements[0]._elements[0]._text) // title field in XML file +console.log('Test: ' + result._declaration._attributes.version) // version field in the XML file +console.log('Test: ' + result._elements[0]._elements[0]._elements[0]._text) // title field in the XML file ``` -Reference: [XML-to-JavaScript Conversion](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-convertxml.md) - -## What are the differences between JavaScript, TypeScript, and eTS? - -Applicable to: OpenHarmony SDK 3.2.3.5, stage model of API version 9 - -- JavaScript: a lightweight, weakly-typed programming language, most commonly known as the scripting language for web pages. - -- TypeScript: a superset of JavaScript, with additions of static typing and more object-oriented APIs, enums, etc. - -- eTS: a superset of TypeScript and the programming language for OpenHarmony ArkUI development, which powers UI development through a declarative development paradigm. +For details, see [XML-to-JavaScript Conversion](../reference/apis/js-apis-convertxml.md). ## How do I convert the time to the HHMMSS format? @@ -93,4 +90,5 @@ export default class DateTimeUtil{ return `${this.fill(hours)}${this.fill(minutes)}${this.fill(seconds)}` } } + ``` diff --git a/en/application-dev/file-management/Readme-EN.md b/en/application-dev/file-management/Readme-EN.md new file mode 100644 index 0000000000000000000000000000000000000000..4bb5fe54817e245807612eaac1a0b6d235101f7a --- /dev/null +++ b/en/application-dev/file-management/Readme-EN.md @@ -0,0 +1,6 @@ +# File Management +- MediaLibrary Management + - [MediaLibrary Overview](medialibrary-overview.md) + - [Media Asset Management](medialibrary-resource-guidelines.md) + - [File Path Management](medialibrary-filepath-guidelines.md) + - [Album Management](medialibrary-album-guidelines.md) \ No newline at end of file diff --git a/en/application-dev/file-management/medialibrary-album-guidelines.md b/en/application-dev/file-management/medialibrary-album-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..fccb8446d5309dbbff0d0687aae8be5ceaf958c8 --- /dev/null +++ b/en/application-dev/file-management/medialibrary-album-guidelines.md @@ -0,0 +1,94 @@ +# Album Management + +You can use the APIs provided by the **mediaLibrary** module to create and delete an album and obtain images in the album. + +> **NOTE** +> +> Before developing features, read [MediaLibrary Overview](medialibrary-overview.md) to learn how to obtain a **MediaLibrary** instance and request the permissions to call the APIs of **MediaLibrary**. + +To ensure the application running efficiency, most **MediaLibrary** API calls are asynchronous, and both callback and promise modes are provided for these APIs. The following code samples use the promise mode. For details about the APIs, see [MediaLibrary API Reference](../reference/apis/js-apis-medialibrary.md). + +## Obtaining Images and Videos in an Album + +You can obtain images and videos in an album in either of the following ways: + +- Call [MediaLibrary.getFileAssets](../reference/apis/js-apis-medialibrary.md#getfileassets7-1) with an album specified to obtain the media assets. For details, see [Querying Media Assets with the Specified Album Name](medialibrary-resource-guidelines.md#querying-media-assets-with-the-specified-album-name). + +- Call [Album.getFileAssets](../reference/apis/js-apis-medialibrary.md#getfileassets7-3) to obtain an **Album** instance, so as to obtain the media assets in it. For details, see [Obtaining Images and Videos in an Album](medialibrary-resource-guidelines.md#obtaining-images-and-videos-in-an-album). + +## Creating an Album + +You can use [MediaLibrary.createAsset](../reference/apis/js-apis-medialibrary.md#createasset8-1), with the relative path set, to create an album while adding a media asset to the album. The relative path is the album name. + +**Prerequisites** + +- You have obtained a **MediaLibrary** instance. +- You have granted the permission **ohos.permission.WRITE_MEDIA**. + +The following describes how to create an album named **myAlbum**. + +**How to Develop** + +1. Call **getPublicDirectory** to obtain the public directory that stores files of a certain type. + + For details about the operation, see [Obtaining a Public Directory](medialibrary-filepath-guidelines.md#obtaining-a-public-directory). + +2. Call **createAsset** to create an image, with the relative path set to **path + 'myAlbum/'**. + + This operation creates an album and adds an image to it. + +```ts +async function example() { + let mediaType = mediaLibrary.MediaType.IMAGE; + let DIR_IMAGE = mediaLibrary.DirectoryType.DIR_IMAGE; + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + const path = await media.getPublicDirectory(DIR_IMAGE) + // myAlbum is the path for storing the new file and the name of the new album. + media.createAsset(mediaType, 'test.jpg', path + 'myAlbum/', (err, fileAsset) => { + if (fileAsset != undefined) { + console.info('createAlbum successfully, message = ' + fileAsset); + } else { + console.info('createAlbum failed, message = ' + err); + } + }); +} +``` + +## Renaming an Album + +Renaming modifies the **FileAsset.albumName** attribute of the album, that is, the album name. After the modification, call [Album.commitModify](../reference/apis/js-apis-medialibrary.md#commitmodify8-3) to commit the modification to the database. + +**Prerequisites** + +- You have obtained a **MediaLibrary** instance. +- You have granted the permission **ohos.permission.WRITE_MEDIA**. + +The following describes how to rename the album **newAlbum**. + +**How to Develop** + +1. Create a retrieval condition for obtaining the target album. +2. Call **getAlbums** to obtain the album list. +3. Rename the album **newAlbum**. +4. Call **Album.commitModify** to commit the modification of the attributes to the database. + +```ts +async function example() { + let AlbumNoArgsfetchOp = { + selections: '', + selectionArgs: [], + }; + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + let albumList = await media.getAlbums(AlbumNoArgsfetchOp); + let album = albumList[0]; + album.albumName = 'newAlbum'; + // Void callback. + album.commitModify().then(function() { + console.info("albumRename successfully"); + }).catch(function(err){ + console.info("albumRename failed with error:"+ err); + }); +} +``` diff --git a/en/application-dev/file-management/medialibrary-filepath-guidelines.md b/en/application-dev/file-management/medialibrary-filepath-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..fc9b327031cfee8ea6de601b3c3d268bbf161c53 --- /dev/null +++ b/en/application-dev/file-management/medialibrary-filepath-guidelines.md @@ -0,0 +1,244 @@ +# File Path Management + +User data on OpenHarmony is managed by the **mediaLibrary** module in a unified manner. You can use the APIs provided by this module to access and operate the user data. + +> **NOTE** +> +> Before developing features, read [MediaLibrary Overview](medialibrary-overview.md) to learn how to obtain a **MediaLibrary** instance and request the permissions to call the APIs of **MediaLibrary**. + +To ensure the application running efficiency, most **MediaLibrary** API calls are asynchronous, and both callback and promise modes are provided for these APIs. The following code samples use the promise mode. For details about the APIs, see [MediaLibrary API Reference](../reference/apis/js-apis-medialibrary.md). + +## File Formats Supported by Public Directories + +Before using file paths for development, learn the file formats supported by each public directory. +> **CAUTION** +> +> The following table lists only the file types that can be identified by the system. In your application development, pay attention to the file formats supported by the corresponding interfaces.
For example, only .jpeg and .webp can be used for image encoding, and only .jpg, .png, .gif, .bmp, .webp, and .raw can be used for image decoding. + +| Directory | Directory Type | Media Type | Description | Supported File Format | +| ---------- | ------------- | ------------- | -------------- | ------------------------------------------------------------ | +| Camera/ | DIR_CAMERA | VIDEO and IMAGE | Directory for storing images and videos taken by the camera. Videos and images can be stored in this directory and its subdirectories.| .bmp / .bm / .gif / .jpg /. jpeg / .jpe / .png / .webp / .raw / .svg / .heif / .mp4 / .3gp / .mpg / .mov / .webm / .mkv | +| Videos/ | DIR_VIDEO | VIDEO | Dedicated video directory. Only videos can be stored in this directory and its subdirectories.| .mp4 / .3gp / .mpg / .mov / .webm / .mkv | +| Pictures/ | DIR_IMAGE | IMAGE | Dedicated image directory. Only images can be stored in this directory and its subdirectories.| .bmp / .bm / .gif / .jpg /. jpeg / .jpe / .png / .webp / .raw / .svg / .heif | +| Audios/ | DIR_AUDIO | AUDIO |Dedicated audio directory. Only audio files can be stored in this directory and its subdirectories.| .aac/.mp3/.flac/.wav/.ogg | +| Documents/ | DIR_DOCUMENTS | FILE |Dedicated file directory. Only files except audios, images, and videos can be stored in this directory and its subdirectories.| - | +| Download/ | DIR_DOWNLOAD | ALLTYPE |Directory for storing downloaded files. The types of files in this directory and its subdirectories are not restricted.| - | + +## Obtaining a Public Directory + +Different types of files are stored in different public directories. You can call [getPublicDirectory](../reference/apis/js-apis-medialibrary.md#getpublicdirectory8-1) to obtain the public directory that stores files of a certain type. + +**Prerequisites** + +- You have obtained a **MediaLibrary** instance. +- You have granted the permission **ohos.permission.READ_MEDIA**. + +The following describes how to obtain the public directory that stores camera files. + +```ts +async function example(){ + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + let DIR_CAMERA = mediaLibrary.DirectoryType.DIR_CAMERA; + const dicResult = await media.getPublicDirectory(DIR_CAMERA); + if (dicResult == 'Camera/') { + console.info('mediaLibraryTest : getPublicDirectory passed'); + } else { + console.info('mediaLibraryTest : getPublicDirectory failed'); + } +} +``` + +## Copying Files Between the Application Sandbox and the Public Directory + +OpenHarmony provides the application sandbox to minimize the leakage of application data and user privacy information. + +Users can access files stored in the public directories through the system applications **Files** and **Gallery**. However, files in the application sandbox can be accessed only by the application itself. + +### Copying a File + +You can call [mediaLibrary.FileAsset.open](../reference/apis/js-apis-medialibrary.md#open8-1) to open a file in a public directory. + +You can call [fileio.open](../reference/apis/js-apis-fileio.md#fileioopen7) to open a file in the application sandbox. The sandbox directory can be accessed only through the application context. + +**Prerequisites** + +- You have obtained a **MediaLibrary** instance. +- You have granted the permission **ohos.permission.WRITE_MEDIA**. +- You have imported the module [@ohos.fileio](../reference/apis/js-apis-fileio.md) in addition to @ohos.multimedia.mediaLibrary. + +**How to Develop** + +1. Call [Context.getFilesDir](../reference/apis/js-apis-Context.md#contextgetfilesdir) to obtain the directory of the application sandbox. +2. Call **MediaLibrary.getFileAssets** and **FetchFileResult.getFirstObject** to obtain the first file in the result set of the public directory. +3. Call **fileio.open** to open the file in the sandbox. +4. Call **fileAsset.open** to open the file in the public directory. +5. Call **fileio.copyfile** to copy the file. +6. Call **fileAsset.close** and **fileio.close** to close the file. + +**Example 1: Copying Files from the Public Directory to the Sandbox** + +```ts +async function copyPublic2Sandbox() { + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + let sandboxDirPath = globalThis.context.filesDir; + let fileKeyObj = mediaLibrary.FileKey + let fileAssetFetchOp = { + selections: fileKeyObj.DISPLAY_NAME + '= ?' , + selectionArgs: ['testFile.txt'], + }; + let fetchResult = await media.getFileAssets(fileAssetFetchOp); + let fileAsset = await fetchResult.getFirstObject(); + + let fdPub = await fileAsset.open('rw'); + let fdSand = await fileio.open(sandboxDirPath + '/testFile.txt', 0o2 | 0o100, 0o666); + await fileio.copyFile(fdPub, fdSand); + + await fileAsset.close(fdPub); + await fileio.close(fdSand); + + let content_sand = await fileio.readText(sandboxDirPath + '/testFile.txt'); + console.log('content read from sandbox file: ', content_sand) +} +``` + +**Example 2: Copying a File from the Sandbox to the Public Directory** + +```ts +async function copySandbox2Public() { + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + let sandboxDirPath = globalThis.context.filesDir; + + let DIR_DOCUMENTS = mediaLibrary.DirectoryType.DIR_DOCUMENTS; + const publicDirPath = await media.getPublicDirectory(DIR_DOCUMENTS); + try { + let fileAsset = await media.createAsset(mediaLibrary.MediaType.FILE, 'testFile02.txt', publicDirPath); + console.info('createFile successfully, message = ' + fileAsset); + } catch (err) { + console.info('createFile failed, message = ' + err); + } + try { + let fileKeyObj = mediaLibrary.FileKey + let fileAssetFetchOp = { + selections: fileKeyObj.DISPLAY_NAME + '= ?' , + selectionArgs: ['testFile02.txt'], + }; + let fetchResult = await media.getFileAssets(fileAssetFetchOp); + var fileAsset = await fetchResult.getFirstObject(); + } catch (err) { + console.info('file asset get failed, message = ', err) + } + var fdPub = await fileAsset.open('rw'); + var fdSand = await fileio.open(sandboxDirPath + 'testFile.txt', 0o2); + await fileio.copyFile(fdSand, fdPub); + await fileio.close(fdPub); + await fileio.close(fdSand); + let fdPubRead = await fileAsset.open('rw'); + try { + var arrayBuffer = new ArrayBuffer(4096); + await fileio.read(fdPubRead, arrayBuffer); + var content_pub = String.fromCharCode(new Uint8Array(arrayBuffer)); + fileAsset.close(fdPubRead); + } catch (err) { + console.log('read text failed, message = ', err); + } + console.log('content read from public file: ', content_pub); +} +``` + +### Reading and Writing a File + +You can use **FileAsset.open** and **FileAsset.close** of [mediaLibrary](../reference/apis/js-apis-medialibrary.md) to open and close a file, and use **fileio.read** and **fileio.write** of [fileio](../reference/apis/js-apis-fileio.md) to read and write a file. + +**Prerequisites** + +- You have obtained a **MediaLibrary** instance. +- You have granted the permission **ohos.permission.WRITE_MEDIA**. +- You have imported the module [@ohos.fileio](../reference/apis/js-apis-fileio.md) in addition to @ohos.multimedia.mediaLibrary. + +**How to Develop** + +1. Create a file. + + ```ts + async function example() { + let mediaType = mediaLibrary.MediaType.FILE; + let DIR_DOCUMENTS = mediaLibrary.DirectoryType.DIR_DOCUMENTS; + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + const path = await media.getPublicDirectory(DIR_DOCUMENTS); + media.createAsset(mediaType, "testFile.text", path).then (function (asset) { + console.info("createAsset successfully:"+ JSON.stringify(asset)); + }).catch(function(err){ + console.info("createAsset failed with error:"+ err); + }); + } + ``` + +2. Call **FileAsset.open** to open the file. + +3. Call **fileio.write** to write a string to the file. + +4. Call **fileio.read** to read the file and save the data read in an array buffer. + +5. Convert the array buffer to a string. + +6. Use **FileAsset.close** to close the file. + +**Example 1: Opening an Existing File and Writing Data to It** + +```ts +async function writeOnlyPromise() { + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + let fileKeyObj = mediaLibrary.FileKey + let fileAssetFetchOp = { + selections: fileKeyObj.DISPLAY_NAME + '= ?' , + selectionArgs: ['testFile.txt'], + }; + let fetchResult = await media.getFileAssets(fileAssetFetchOp); + let fileAsset = await fetchResult.getFirstObject(); + console.info('fileAssetName: ', fileAsset.displayName); + + try { + let fd = await fileAsset.open('w'); + console.info('file descriptor: ', fd); + await fileio.write(fd, "Write file test content."); + await fileAsset.close(fd); + } catch (err) { + console.info('write file failed, message = ', err); + } +} +``` + +**Example 2: Opening an Existing File and Reading Data from It** + +```ts +async function readOnlyPromise() { + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + let fileKeyObj = mediaLibrary.FileKey + let fileAssetFetchOp = { + selections: fileKeyObj.DISPLAY_NAME + '= ?' , + selectionArgs: ['testFile.txt'], + }; + let fetchResult = await media.getFileAssets(fileAssetFetchOp); + let fileAsset = await fetchResult.getFirstObject(); + console.info('fileAssetName: ', fileAsset.displayName); + + try { + let fd = await fileAsset.open('r'); + let arrayBuffer = new ArrayBuffer(4096); + await fileio.read(fd, arrayBuffer); + let fileContent = String.fromCharCode(...new Uint8Array(arrayBuffer)); + globalThis.fileContent = fileContent + globalThis.fileName = fileAsset.displayName; + console.info('file content: ', fileContent); + await fileAsset.close(fd); + } catch (err) { + console.info('read file failed, message = ', err); + } +} +``` diff --git a/en/application-dev/file-management/medialibrary-overview.md b/en/application-dev/file-management/medialibrary-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..79f13fe066967607ab15f096fe3ce5478aaa9abe --- /dev/null +++ b/en/application-dev/file-management/medialibrary-overview.md @@ -0,0 +1,127 @@ +# MediaLibrary Development Overview + +The **mediaLibrary** module provides APIs for you to access and modify media files. + +- You can manage [media assets (audios, videos, image, and files)](medialibrary-resource-guidelines.md) as follows: + - Query media assets. + - Obtain an image or a video. + - Obtain the thumbnail of an image or a video. + - Create a media asset. + - Rename a media asset. + - Move a media asset to the recycle bin. +- You can manage [file paths](medialibrary-filepath-guidelines.md) as follows: + - Obtain the public directory that stores files of a certain type. + - Copy files between the application sandbox and the public directory. + - Read and write a file. +- You can manage [albums](medialibrary-album-guidelines.md) as follows: + - Obtain images and videos in an album. + - Create an album. + - Rename an album. + +> **NOTE** +> +> This development guide applies only to the stage model (available from API version 9). + +To access and modify personal media data, an application must obtain a **MediaLibrary** instance and request the media asset read and write permissions from the user. + +Before using the **MediaLibrary** APIs to develop features, you must learn how to: + +- [Obtain a MediaLibrary Instance](#obtaining-a-medialibrary-instance) +- [Request Permissions](#requesting-permissions) + +## Obtaining a MediaLibrary Instance + +An application must call [getMediaLibrary](../reference/apis/js-apis-medialibrary.md#medialibrarygetmedialibrary8) to obtain a **MediaLibrary** instance based on the application context. Through this instance, the application can access and modify personal media data (such as audios, videos, images, and files). + +**How to Develop** + +1. Import the **mediaLibrary** module. +2. Call **getContext** to obtain the application context. +3. Obtain a **MediaLibrary** instance. + +```ts +import mediaLibrary from '@ohos.multimedia.mediaLibrary'; + +const context = getContext(this); +var media = mediaLibrary.getMediaLibrary(context); +``` + +## Requesting Permissions + +To read and write a **MediaLibrary** instance, you must have the required permissions, as described in the table below. Before requesting the permissions, ensure that the [basic principles for permission management](../security/accesstoken-overview.md#basic-principles-for-permission-management) are met. + +| Permission | Description | Authorization Mode | +| ------------------------------ | ------------------------------------------ | ---------- | +| ohos.permission.READ_MEDIA | Allows an application to read media files from the user's external storage.| user_grant | +| ohos.permission.WRITE_MEDIA | Allows an application to read media files from and write media files into the user's external storage.| user_grant | +| ohos.permission.MEDIA_LOCATION | Allows an application to access geographical locations in the user's media file.| user_grant | + +After configuring the permissions in the **module.json5** file, the application must call [Context.requestPermissionsFromUser](../reference/apis/js-apis-ability-context.md#abilitycontextrequestpermissionsfromuser) to check for the required permissions and if they are not granted, request the permissions from the user by displaying a dialog box. + +> **NOTE**
Even if the user has granted a permission, the application must check for the permission before calling an API protected by the permission. It should not persist the permission granted status, because the user can revoke the permission through the system application **Settings**. + +**How to Develop** + +1. Declare the permissions in the **module.json5** file. Add the **requestPermissions** tag under **module** in the file, and set the tag based on the project requirements. For details about the tag, see [Guide for Requesting Permissions from User](../security/accesstoken-guidelines.md). + + ```json + { + "module": { + "requestPermissions": [ + { + "name": "ohos.permission.MEDIA_LOCATION", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "MainAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.READ_MEDIA", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "MainAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.WRITE_MEDIA", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "MainAbility" + ], + "when": "always" + } + } + ] + } + } + ``` + +2. Call **requestPermissionsFromUser** to check for the required permissions and if they are not granted, request the permissions from the user by displaying a dialog box. + + ```ts + import Ability from '@ohos.application.Ability' + + export default class MainAbility extends Ability { + onWindowStageCreate(windowStage) { + var permissions=['ohos.permission.READ_MEDIA','ohos.permission.WRITE_MEDIA'] + var permissionRequestResult; + this.context.requestPermissionsFromUser(permissions,(err,result) => { + if(err){ + console.log('requestPermissionsFromUserError: ' + JSON.stringify(err)); + }else{ + permissionRequestResult=result; + console.log('permissionRequestResult: ' + JSON.stringify(permissionRequestResult)); + } + }); + } + } + ``` + + diff --git a/en/application-dev/file-management/medialibrary-resource-guidelines.md b/en/application-dev/file-management/medialibrary-resource-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..d3ca37dc5be9163a4de8c303aa81704d95056bc1 --- /dev/null +++ b/en/application-dev/file-management/medialibrary-resource-guidelines.md @@ -0,0 +1,385 @@ +# Media Asset Management + +Your applications can use the APIs provided by the **mediaLibrary** module to perform operations on media assets such as audios, videos, images, and files. + +> **NOTE** +> +> Before developing features, read [MediaLibrary Overview](medialibrary-overview.md) to learn how to obtain a **MediaLibrary** instance and request the permissions to call the APIs of **MediaLibrary**. + +To maximize the application running efficiency, most **MediaLibrary** API calls are asynchronous in callback or promise mode. The following code samples use the promise mode. For details about the APIs, see [MediaLibrary API Reference](../reference/apis/js-apis-medialibrary.md). + +## Querying Media Assets + +You can query media assets by condition such as the media type, date, or album name. + +To do so, call [MediaLibrary.getFileAssets](../reference/apis/js-apis-medialibrary.md#getfileassets7-1), with a **MediaFetchOptions** object passed in to specify the conditions. In this object, **MediaFetchOptions.selections** are the retrieval conditions, and the enumerated values of **FileKey** are used as the column names of the conditions; **MediaFetchOptions.selectionArgs** are the values of the conditions. You can also specify **order** (sorting mode of the search result), **uri** (file URI), and **networkId** (network ID of the registered device) as the conditions. + +To obtain the object at the specified position (for example, the first, the last, or with the specified index) in the result set, call [FetchFileResult](../reference/apis/js-apis-medialibrary.md#fetchfileresult7). In this section, **getNextObject** is used cyclically to obtain all media assets in the result set. + +**Prerequisites** + +- You have obtained a **MediaLibrary** instance. +- You have granted the permission **ohos.permission.READ_MEDIA**. + +### Querying Media Assets with the Specified Media Type + +The following describes how to obtain images. + +**How to Develop** + +To specify the media type as the retrieval condition, set **selections** to **FileKey.MEDIA_TYPE**. + +To specify the image as the media type, set **selectionArgs** to **MediaType.IMAGE**. + +```ts +async function example() { + let fileKeyObj = mediaLibrary.FileKey + let fileType = mediaLibrary.MediaType.IMAGE + let option = { + selections: fileKeyObj.MEDIA_TYPE + '= ?', + selectionArgs: [fileType.toString()], + }; + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + const fetchFileResult = await media.getFileAssets(option); + for (let i = 0; i < fetchFileResult.getCount(); i++) { + fetchFileResult.getNextObject((err, fileAsset) => { + if (err) { + console.error('Failed '); + return; + } + console.log('fileAsset.displayName ' + i + ': ' + fileAsset.displayName); + }) + } +} +``` + +### Querying Media Assets with the Specified Date + +The following describes how to obtain media assets that are added on the specified date. You can also use the modification date and shooting date as the retrieval conditions. + +To specify the date when the files are added as the retrieval condition, set **selections** to **FileKey.DATE_ADDED**. + +To specify the date 2022-8-5, set **selectionArgs** to **2022-8-5**. + +```ts +async function example() { + let fileKeyObj = mediaLibrary.FileKey + let option = { + selections: fileKeyObj.DATE_ADDED + '= ?', + selectionArgs: ['2022-8-5'], + }; + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + const fetchFileResult = await media.getFileAssets(option); + for (let i = 0; i < fetchFileResult.getCount(); i++) { + fetchFileResult.getNextObject((err, fileAsset) => { + if (err) { + console.error('Failed '); + return; + } + console.log('fileAsset.displayName ' + i + ': ' + fileAsset.displayName); + }) + } +} +``` + +### Querying Media Assets and Sorting Them + +The following describes how to query images and sort them in descending order by the date when they are added. You can also sort them in ascending order. + +To sort files in descending order by the date when they are added, set **order** to **FileKey.DATE_ADDED + " DESC"**. + +```ts +async function example() { + let fileKeyObj = mediaLibrary.FileKey + let fileType = mediaLibrary.MediaType.IMAGE + let option = { + selections: fileKeyObj.MEDIA_TYPE + '= ?', + selectionArgs: [fileType.toString()], + order: fileKeyObj.DATE_ADDED + " DESC", + }; + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + const fetchFileResult = await media.getFileAssets(option); + for (let i = 0; i < fetchFileResult.getCount(); i++) { + fetchFileResult.getNextObject((err, fileAsset) => { + if (err) { + console.error('Failed '); + return; + } + console.log('fileAsset.displayName ' + i + ': ' + fileAsset.displayName); + }) + } +} +``` + +### Querying Media Assets with the Specified Album Name + +The following describes how to query media assets in **myAlbum**. + +To specify the album name as the retrieval condition, set **selections** to **FileKey.ALBUM_NAME**. + +To specify the album name **'myAlbum'**, set **selectionArgs** to **'myAlbum'**. + +```ts +async function example() { + let fileKeyObj = mediaLibrary.FileKey + let fileType = mediaLibrary.MediaType.IMAGE + let option = { + selections: fileKeyObj.ALBUM_NAME + '= ?', + selectionArgs: ['myAlbum'], + }; + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + const fetchFileResult = await media.getFileAssets(option); + for (let i = 0; i < fetchFileResult.getCount(); i++) { + fetchFileResult.getNextObject((err, fileAsset) => { + if (err) { + console.error('Failed '); + return; + } + console.log('fileAsset.displayName ' + i + ': ' + fileAsset.displayName); + }) + } +} +``` + +## Obtaining Images and Videos in an Album + +You can obtain media assets in an album in either of the following ways: + +- Call [MediaLibrary.getFileAssets](../reference/apis/js-apis-medialibrary.md#getfileassets7-1) with an album specified, as described in [Querying Media Assets with the Specfied Album Name](#querying-media-assets-with-the-specified-album-name). +- Call [Album.getFileAssets](../reference/apis/js-apis-medialibrary.md#getfileassets7-3) to obtain an **Album** instance, so as to obtain the media assets in it. + +**Prerequisites** + +- You have obtained a **MediaLibrary** instance. +- You have granted the permission **ohos.permission.READ_MEDIA**. + +**How to Develop** + +The following describes how to obtain videos in an album named **New Album 1**. + +1. Create a retrieval condition for obtaining the target **Album** instance. + + ```ts + let fileKeyObj = mediaLibrary.FileKey; + let AlbumNoArgsFetchOp = { + selections: fileKeyObj.ALBUM_NAME + '= ?', + selectionArgs:['New Album 1'] + } + ``` + +2. Create a retrieval condition for obtaining videos in the target album. + + ```ts + let fileKeyObj = mediaLibrary.FileKey; + let imageType = mediaLibrary.MediaType.VIDEO; + let imagesFetchOp = { + selections: fileKeyObj.MEDIA_TYPE + '= ?', + selectionArgs: [imageType.toString()], + } + ``` + +3. Call **Album.getFileAssets** to obtain the videos in the target album. + +Complete sample code: + +```ts +async function getCameraImagePromise() { + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + let fileKeyObj = mediaLibrary.FileKey; + let imageType = mediaLibrary.MediaType.IMAGE; + let imagesFetchOp = { + selections: fileKeyObj.MEDIA_TYPE + '= ?', + selectionArgs: [imageType.toString()], + } + let AlbumNoArgsFetchOp = { + selections: fileKeyObj.ALBUM_NAME + '= ?', + selectionArgs:['New Album 1'] + } + + let albumList = await media.getAlbums(AlbumNoArgsFetchOp); + if (albumList.length > 0) { + const album = albumList[0]; + let fetchFileResult = await album.getFileAssets(imagesFetchOp); + let count = fetchFileResult.getCount(); + console.info("get mediaLibrary IMAGE number", count); + } else { + console.info('getAlbum list is: 0'); + } +} +``` + +## Obtaining the Thumbnail of an Image or a Video + +You can call [FileAsset.getThumbnail](../reference/apis/js-apis-medialibrary.md#getthumbnail8-2) with the thumbnail size passed in to obtain the thumbnail of an image or a video. Your application can use thumbnails to offer a quick preview on images and videos. + +**Prerequisites** + +- You have obtained a **MediaLibrary** instance. +- You have granted the permission **ohos.permission.READ_MEDIA**. + +### Obtaining the Thumbnail of an Image + +The following describes how to obtain the thumbnail (size: 720 x 720) of the first image in the album. + +**How to Develop** + +1. Create a retrieval condition for obtaining images in the target album. +2. Call **getFileAssets** to obtain the images in the target album. +3. Call **getFirstObject** to obtain the first image among all the images obtained. +4. Call **getThumbnail** to obtain the thumbnail of the first image. + +```ts +async function getFirstThumbnailPromise() { + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + let fileKeyObj = mediaLibrary.FileKey; + let imageType = mediaLibrary.MediaType.IMAGE; + let imagesFetchOp = { + selections: fileKeyObj.MEDIA_TYPE + '= ?', + selectionArgs: [imageType.toString()], + } + + let size = { width: 720, height: 720 }; + const fetchFileResult = await media.getFileAssets(imagesFetchOp); + if (fetchFileResult != undefined) { + const asset = await fetchFileResult.getFirstObject(); + asset.getThumbnail(size).then((pixelMap) => { + pixelMap.getImageInfo().then((info) => { + console.info('get Thumbnail info: ' + "width: " + info.size.width + " height: " + info.size.height); + }).catch((err) => { + console.info("getImageInfo failed with error:" + err); + }); + }).catch((err) => { + console.info("getImageInfo failed with error:" + err); + }); + } else { + console.info("get image failed with error"); + } +} +``` + +## Creating a Media Asset + +You can call [MediaLibrary.createAsset](../reference/apis/js-apis-medialibrary.md#createasset8-1) to create a media asset. + +**Prerequisites** + +- You have obtained a **MediaLibrary** instance. +- You have granted the permission **ohos.permission.WRITE_MEDIA**. +- [You have obtained a public directory](medialibrary-filepath-guidelines.md). + +The following describes how to create a file of the **MediaType.FILE** type. + +```ts +async function example() { + let mediaType = mediaLibrary.MediaType.FILE; + let DIR_DOCUMENTS = mediaLibrary.DirectoryType.DIR_DOCUMENTS; + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + const path = await media.getPublicDirectory(DIR_DOCUMENTS); + media.createAsset(mediaType, "testFile.text", path).then ((asset) => { + console.info("createAsset successfully:"+ JSON.stringify(asset)); + }).catch((err) => { + console.info("createAsset failed with error:"+ err); + }); +} +``` + +## Moving a Media Asset to the Recycle Bin + +You can use [FileAsset.trash](../reference/apis/js-apis-medialibrary.md#trash8) to move a media asset to the recycle bin. + +By default, files in the recycle bin will be stored for 30 days before being permanently removed. During this period, you can set **isTrash** in **trash** to **false** to recover the files. Application users can also recover the files through the system applications **Files** or **Gallery**. + +**Prerequisites** + +- You have obtained a **MediaLibrary** instance. +- You have granted the permission **ohos.permission.WRITE_MEDIA**. + +The following describes how to move the first file in the result set to the recycle bin. + +**How to Develop** + +1. Create a retrieval condition for obtaining images in the target album. +2. Call **getFileAssets** to obtain the images in the target album. +3. Call **getFirstObject** to obtain the first image among all the images obtained. +4. Call **trash** to move the first image to the recycle bin. + +```ts +async function example() { + let fileKeyObj = mediaLibrary.FileKey + let fileType = mediaLibrary.MediaType.FILE + let option = { + selections: fileKeyObj.MEDIA_TYPE + '= ?', + selectionArgs: [fileType.toString()], + }; + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + const fetchFileResult = await media.getFileAssets(option); + let asset = await fetchFileResult.getFirstObject(); + if (asset == undefined) { + console.error('asset not exist') + return + } + // Void callback. + asset.trash(true).then(() => { + console.info("trash successfully"); + }).catch((err) => { + console.info("trash failed with error:"+ err); + }); +} +``` + +## Renaming a Media Asset + +To rename a media asset, modify the **FileAsset.displayName** attribute (which specifies the displayed file name, including the file name extension) and commit the modification through [FileAsset.commitModify](../reference/apis/js-apis-medialibrary.md#commitmodify8-1). + +Before renaming a file, you must obtain the file, for example, by calling [FetchFileResult](../reference/apis/js-apis-medialibrary.md#fetchfileresult7). + +**Prerequisites** + +- You have obtained a **MediaLibrary** instance. +- You have granted the permission **ohos.permission.WRITE_MEDIA**. + +The following describes how to rename the first file in the result set as **newtitle.text**. + +**How to Develop** + +1. Create a retrieval condition for obtaining images in the target album. +2. Call **getFileAssets** to obtain the images in the target album. +3. Call **getFirstObject** to obtain the first image among all the images obtained. +4. Rename the image as **newImage.jpg**. +5. Call **FileAsset.commitModify** to commit the modification to the database. + +```ts +async function example() { + let fileKeyObj = mediaLibrary.FileKey + let fileType = mediaLibrary.MediaType.FILE + let option = { + selections: fileKeyObj.MEDIA_TYPE + '= ?', + selectionArgs: [fileType.toString()], + }; + const context = getContext(this); + var media = mediaLibrary.getMediaLibrary(context); + const fetchFileResult = await media.getFileAssets(option); + let asset = await fetchFileResult.getFirstObject(); + if (asset == undefined) { + console.error('asset not exist') + return + } + asset.displayName = 'newImage.jpg'; + // Void callback. + asset.commitModify((err) => { + if (err) { + console.error('fileRename Failed '); + return; + } + console.log('fileRename successful.'); + }) +} +``` diff --git a/en/application-dev/internationalization/i18n-guidelines.md b/en/application-dev/internationalization/i18n-guidelines.md index 4c293fdee7114866ebd969151c0914d29a144941..62bf66fd7cabb7e30c765126ddacba639bd951f5 100644 --- a/en/application-dev/internationalization/i18n-guidelines.md +++ b/en/application-dev/internationalization/i18n-guidelines.md @@ -9,15 +9,15 @@ You can use APIs provided in the following table to obtain the system language a ### Available APIs -| Module | API | Description | +| Module | API | Description | | -------- | -------- | -------- | -| ohos.i18n | getSystemLanguage(): string | Obtains the system language. | -| ohos.i18n | getSystemRegion(): string | Obtains the system region. | -| ohos.i18n | getSystemLocale(): string | Obtains the system locale. | -| ohos.i18n | isRTL(locale: string): boolean7+ | Checks whether the locale uses a right-to-left (RTL) language. | -| ohos.i18n | is24HourClock(): boolean7+ | Checks whether the system uses a 24-hour clock. | -| ohos.i18n | getDisplayLanguage(language: string, locale: string, sentenceCase?: boolean): string | Obtains the localized display of a language. | -| ohos.i18n | getDisplayCountry(country: string, locale: string, sentenceCase?: boolean): string | Obtains the localized display of a country name. | +| ohos.i18n | getSystemLanguage(): string | Obtains the system language. | +| ohos.i18n | getSystemRegion(): string | Obtains the system region. | +| ohos.i18n | getSystemLocale(): string | Obtains the system locale. | +| ohos.i18n | isRTL(locale: string): boolean7+ | Checks whether the locale uses a right-to-left (RTL) language. | +| ohos.i18n | is24HourClock(): boolean7+ | Checks whether the system uses a 24-hour clock. | +| ohos.i18n | getDisplayLanguage(language: string, locale: string, sentenceCase?: boolean): string | Obtains the localized display of a language. | +| ohos.i18n | getDisplayCountry(country: string, locale: string, sentenceCase?: boolean): string | Obtains the localized display of a country name. | ### How to Develop @@ -26,7 +26,7 @@ You can use APIs provided in the following table to obtain the system language a Call the **getSystemLanguage** method to obtain the system language (**i18n** is the name of the imported module). - + ```js var language = i18n.getSystemLanguage(); ``` @@ -42,7 +42,7 @@ You can use APIs provided in the following table to obtain the system language a 3. Obtain the system locale. Call the **getSystemLocale** method to obtain the system locale. - + ```js var locale = i18n.getSystemLocale(); ``` @@ -51,7 +51,7 @@ You can use APIs provided in the following table to obtain the system language a Call the **isRTL** method to check whether the locale's language is RTL. - + ```js var rtl = i18n.isRTL("zh-CN"); ``` @@ -67,7 +67,7 @@ You can use APIs provided in the following table to obtain the system language a 6. Obtain the localized display of a language. Call the **getDisplayLanguage** method to obtain the localized display of a language. **language** indicates the language to be localized, **locale** indicates the locale, and **sentenceCase** indicates whether the first letter of the result must be capitalized. - + ```js var language = "en"; var locale = "zh-CN"; @@ -78,7 +78,7 @@ You can use APIs provided in the following table to obtain the system language a 7. Obtain the localized display of a country. Call the **getDisplayCountry** method to obtain the localized display of a country name. **country** indicates the country code (a two-letter code in compliance with ISO-3166, for example, CN), **locale** indicates the locale, and **sentenceCase** indicates whether the first letter of the result must be capitalized. - + ```js var country = "US"; var locale = "zh-CN"; @@ -116,7 +116,7 @@ You can use APIs provided in the following table to obtain the system language a Call the **getCalendar** method to obtain the time zone object of a specific locale and type (**i18n** is the name of the imported module). **type** indicates the valid calendar type, for example, **buddhist**, **chinese**, **coptic**, **ethiopic**, **hebrew**, **gregory**, **indian**, **islamic_civil**, **islamic_tbla**, **islamic_umalqura**, **japanese**, and **persian**. If **type** is left unspecified, the default calendar type of the locale is used. - + ```js var calendar = i18n.getCalendar("zh-CN", "gregory"); ``` @@ -135,7 +135,7 @@ You can use APIs provided in the following table to obtain the system language a 3. Set the year, month, day, hour, minute, and second for the **Calendar** object. Call the **set** method to set the year, month, day, hour, minute, and second for the **Calendar** object. - + ```js calendar.set(2021, 12, 21, 6, 0, 0) ``` @@ -144,7 +144,7 @@ You can use APIs provided in the following table to obtain the system language a Call the **setTimeZone** and **getTimeZone** methods to set and obtain the time zone for the **Calendar** object. The **setTimeZone** method requires an input string to indicate the time zone to be set. - + ```js calendar.setTimeZone("Asia/Shanghai"); var timezone = calendar.getTimeZone(); @@ -163,7 +163,7 @@ You can use APIs provided in the following table to obtain the system language a 6. Set and obtain the minimum count of days in the first week for the **Calendar** object. Call the **setMinimalDaysInFirstWeek** and **getMinimalDaysInFirstWeek** methods to set and obtain the minimum count of days in the first week for the **Calendar** object. - + ```js calendar.setMinimalDaysInFirstWeek(3); var minimalDaysInFirstWeek = calendar.getMinimalDaysInFirstWeek(); @@ -173,7 +173,7 @@ You can use APIs provided in the following table to obtain the system language a Call the **getDisplayName** method to obtain the localized display of the **Calendar** object. - + ```js var localizedName = calendar.getDisplayName("zh-CN"); ``` @@ -196,11 +196,11 @@ You can use APIs provided in the following table to obtain the system language a ### Available APIs -| Module | API | Description | +| Module | API | Description | | -------- | -------- | -------- | -| ohos.i18n | constructor(country: string, options?: PhoneNumberFormatOptions)8+ | Instantiates a **PhoneNumberFormat** object. | -| ohos.i18n | isValidNumber(number: string): boolean8+ | Checks whether the value of **number** is a phone number in the correct format. | -| ohos.i18n | format(number: string): string8+ | Formats the value of **number** based on the specified country and style. | +| ohos.i18n | constructor(country: string, options?: PhoneNumberFormatOptions)8+ | Instantiates a **PhoneNumberFormat** object. | +| ohos.i18n | isValidNumber(number: string): boolean8+ | Checks whether the value of **number** is a phone number in the correct format. | +| ohos.i18n | format(number: string): string8+ | Formats the value of **number** based on the specified country and style. | ### How to Develop @@ -209,7 +209,7 @@ You can use APIs provided in the following table to obtain the system language a Call the **PhoneNumberFormat** constructor to instantiate a **PhoneNumberFormat** object. The country code and formatting options of the phone number need to be passed into this constructor. The formatting options are optional, including a style option. Values of this option include: **E164**, **INTERNATIONAL**, **NATIONAL**, and **RFC3966**. - + ```js var phoneNumberFormat = new i18n.PhoneNumberFormat("CN", {type: "E164"}); ``` @@ -223,7 +223,7 @@ You can use APIs provided in the following table to obtain the system language a 3. Format a phone number. Call the **format** method of **PhoneNumberFormat** to format the input phone number. - + ```js var formattedNumber = phoneNumberFormat.format("15812341234"); ``` @@ -236,15 +236,15 @@ The **unitConvert** API is provided to help you implement measurement conversion ### Available APIs -| Module | API | Description | +| Module | API | Description | | -------- | -------- | -------- | -| ohos.i18n | unitConvert(fromUnit: UnitInfo, toUnit: UnitInfo, value: number, locale: string, style?: string): string8+ | Converts one measurement unit (**fromUnit**) into another (**toUnit**) and formats the unit based on the specified locale and style. | +| ohos.i18n | unitConvert(fromUnit: UnitInfo, toUnit: UnitInfo, value: number, locale: string, style?: string): string8+ | Converts one measurement unit (**fromUnit**) into another (**toUnit**) and formats the unit based on the specified locale and style. | ### How to Develop 1. Convert a measurement unit. - Call the [unitConvert](../reference/apis/js-apis-i18n.md#unitconvert8) method to convert a measurement unit and format the display result. + Call the [unitConvert](../reference/apis/js-apis-i18n.md#unitconvert9) method to convert a measurement unit and format the display result. ```js @@ -254,7 +254,7 @@ The **unitConvert** API is provided to help you implement measurement conversion var locale = "en-US"; var style = "long"; i18n.Util.unitConvert(fromUtil, toUtil, number, locale, style); - ``` + ``` ## Alphabet Index @@ -278,7 +278,7 @@ The **unitConvert** API is provided to help you implement measurement conversion Call the **getInstance** method to instantiate an **IndexUtil** object for a specific locale. When the **locale** parameter is empty, instantiate an **IndexUtil** object of the default locale. - + ```js var indexUtil = i18n.getInstance("zh-CN"); ``` @@ -294,7 +294,7 @@ The **unitConvert** API is provided to help you implement measurement conversion 3. Add an index. Call the **addLocale** method to add the alphabet index of a new locale to the current index list. - + ```js indexUtil.addLocale("ar") ``` @@ -302,7 +302,7 @@ The **unitConvert** API is provided to help you implement measurement conversion 4. Obtain the index of a string. Call the **getIndex** method to obtain the alphabet index of a string. - + ```js var text = "access index"; indexUtil.getIndex(text); @@ -336,7 +336,7 @@ When a text is displayed in more than one line, [BreakIterator8](../reference/ap Call the **getLineInstance** method to instantiate a **BreakIterator** object. - + ```js var locale = "en-US" var breakIterator = i18n.getLineInstance(locale); @@ -357,7 +357,7 @@ When a text is displayed in more than one line, [BreakIterator8](../reference/ap Call the **current** method to obtain the current position of the **BreakIterator** object in the text being processed. - + ```js var pos = breakIterator.current(); ``` @@ -383,7 +383,9 @@ When a text is displayed in more than one line, [BreakIterator8](../reference/ap Call the **isBoundary** method to determine whether a position is a break point. If yes, **true** is returned and the **BreakIterator** object is moved to this position. If no, **false** is returned and the **BreakIterator** object is moved to a break point after this position. - + ```js var isboundary = breakIterator.isBoundary(5); ``` + + ``` \ No newline at end of file diff --git a/en/application-dev/internationalization/intl-guidelines.md b/en/application-dev/internationalization/intl-guidelines.md index 424320dcc17f3dc0eb6d3e30970869da83874408..f123a0b29a64a10b683f9fb90d163790e4f0524e 100644 --- a/en/application-dev/internationalization/intl-guidelines.md +++ b/en/application-dev/internationalization/intl-guidelines.md @@ -13,13 +13,13 @@ Use [Locale](../reference/apis/js-apis-intl.md#locale) APIs to maximize or minim ### Available APIs -| Module | API | Description | +| Module | API | Description | | -------- | -------- | -------- | -| ohos.intl | constructor()8+ | Instantiates a **Locale** object. | -| ohos.intl | constructor(locale?: string, options?: options) | Instantiates a **Locale** object based on the locale parameter and options. | -| ohos.intl | toString(): string | Converts locale information into a string. | -| ohos.intl | maximize(): Locale | Maximizes locale information. | -| ohos.intl | minimize(): Locale | Minimizes locale information. | +| ohos.intl | constructor()8+ | Instantiates a **Locale** object. | +| ohos.intl | constructor(locale?: string, options?: options) | Instantiates a **Locale** object based on the locale parameter and options. | +| ohos.intl | toString(): string | Converts locale information into a string. | +| ohos.intl | maximize(): Locale | Maximizes locale information. | +| ohos.intl | minimize(): Locale | Minimizes locale information. | ### How to Develop @@ -45,7 +45,7 @@ Use [Locale](../reference/apis/js-apis-intl.md#locale) APIs to maximize or minim ```js var locale = "zh-CN"; - var options = {caseFirst: false, calendar: "chinese", collation: "pinyin"}; + var options = {caseFirst: "false", calendar: "chinese", collation: "pinyin"}; var localeObj = new intl.Locale(locale, options); ``` @@ -81,13 +81,13 @@ Use [DateTimeFormat](../reference/apis/js-apis-intl.md#datetimeformat) APIs to f ### Available APIs -| Module | API | Description | +| Module | API | Description | | -------- | -------- | -------- | -| ohos.intl | constructor()8+ | Creates a **DateTimeFormat** object. | -| ohos.intl | constructor(locale: string \| Array<string>, options?: DateTimeOptions) | Creates a **DateTimeFormat** object and sets the locale and other formatting-related attributes. | -| ohos.intl | format(date: Date): string | Calculates the date and time based on the locale and other formatting-related attributes of the **DateTimeFormat** object. | -| ohos.intl | formatRange(startDate: Date, endDate: Date): string | Calculates the period based on the locale and other formatting-related attributes of the **DateTimeFormat** object. | -| ohos.intl | resolvedOptions(): DateTimeOptions | Obtains the related attributes of the **DateTimeFormat** object. | +| ohos.intl | constructor()8+ | Creates a **DateTimeFormat** object. | +| ohos.intl | constructor(locale: string \| Array<string>, options?: DateTimeOptions) | Creates a **DateTimeFormat** object and sets the locale and other formatting-related attributes. | +| ohos.intl | format(date: Date): string | Calculates the date and time based on the locale and other formatting-related attributes of the **DateTimeFormat** object. | +| ohos.intl | formatRange(startDate: Date, endDate: Date): string | Calculates the period based on the locale and other formatting-related attributes of the **DateTimeFormat** object. | +| ohos.intl | resolvedOptions(): DateTimeOptions | Obtains the related attributes of the **DateTimeFormat** object. | ### How to Develop @@ -144,12 +144,12 @@ Use [NumberFormat](../reference/apis/js-apis-intl.md#numberformat) APIs to forma ### Available APIs -| Module | API | Description | +| Module | API | Description | | -------- | -------- | -------- | -| ohos.intl | constructor()8+ | Creates a **NumberFormat** object. | -| ohos.intl | constructor(locale: string \| Array<string>, options?: NumberOptions) | Creates a **NumberFormat** object and sets the locale and other formatting-related attributes. | -| ohos.intl | format(number: number): string | Calculates the number based on the locale and other formatting-related attributes of the **NumberFormat** object. | -| ohos.intl | resolvedOptions(): NumberOptions | Obtains attributes of the **NumberFormat** object. | +| ohos.intl | constructor()8+ | Creates a **NumberFormat** object. | +| ohos.intl | constructor(locale: string \| Array<string>, options?: NumberOptions) | Creates a **NumberFormat** object and sets the locale and other formatting-related attributes. | +| ohos.intl | format(number: number): string | Calculates the number based on the locale and other formatting-related attributes of the **NumberFormat** object. | +| ohos.intl | resolvedOptions(): NumberOptions | Obtains attributes of the **NumberFormat** object. | ### How to Develop @@ -195,12 +195,12 @@ Use [Collator](../reference/apis/js-apis-intl.md#collator8) APIs to sort strings ### Available APIs -| Module | API | Description | +| Module | API | Description | | -------- | -------- | -------- | -| ohos.intl | constructor()8+ | Creates a **Collator** object. | -| ohos.intl | constructor(locale: string \| Array<string>, options?: CollatorOptions)8+ | Creates a **Collator** object and sets the locale and other related attributes. | -| ohos.intl | compare(first: string, second: string): number8+ | Calculates the comparison result of two strings based on the locale and other attributes of the **Collator** object. | -| ohos.intl | resolvedOptions(): CollatorOptions8+ | Obtains attributes of the **Collator** object. | +| ohos.intl | constructor()8+ | Creates a **Collator** object. | +| ohos.intl | constructor(locale: string \| Array<string>, options?: CollatorOptions)8+ | Creates a **Collator** object and sets the locale and other related attributes. | +| ohos.intl | compare(first: string, second: string): number8+ | Calculates the comparison result of two strings based on the locale and other attributes of the **Collator** object. | +| ohos.intl | resolvedOptions(): CollatorOptions8+ | Obtains attributes of the **Collator** object. | ### How to Develop @@ -214,7 +214,7 @@ Use [Collator](../reference/apis/js-apis-intl.md#collator8) APIs to sort strings var collator = new intl.Collator(); ``` - Alternatively, use your own locale and formatting parameters to create a **Collator** object. For a full list of parameters, see [CollatorOptions](../reference/apis/js-apis-intl.md#collatoroptions8). + Alternatively, use your own locale and formatting parameters to create a **Collator** object. For a full list of parameters, see [CollatorOptions](../reference/apis/js-apis-intl.md#collatoroptions9). ```js var collator= new intl.Collator("zh-CN", {localeMatcher: "best fit", usage: "sort"}); @@ -246,11 +246,11 @@ Use [PluralRules](../reference/apis/js-apis-intl.md#pluralrules8) APIs to determ ### Available APIs -| Module | API | Description | +| Module | API | Description | | -------- | -------- | -------- | -| ohos.intl | constructor()8+ | Creates a **PluralRules** object. | -| ohos.intl | constructor(locale: string \| Array<string>, options?: PluralRulesOptions)8+ | Creates a **PluralRules** object and sets the locale and other related attributes. | -| ohos.intl | select(n: number): string8+ | Determines the singular-plural type based on the locale and other formatting-related attributes of the **PluralRules** object. | +| ohos.intl | constructor()8+ | Creates a **PluralRules** object. | +| ohos.intl | constructor(locale: string \| Array<string>, options?: PluralRulesOptions)8+ | Creates a **PluralRules** object and sets the locale and other related attributes. | +| ohos.intl | select(n: number): string8+ | Determines the singular-plural type based on the locale and other formatting-related attributes of the **PluralRules** object. | ### How to Develop @@ -264,7 +264,7 @@ Use [PluralRules](../reference/apis/js-apis-intl.md#pluralrules8) APIs to determ var pluralRules = new intl.PluralRules(); ``` - Alternatively, use your own locale and formatting parameters to create a **PluralRules** object. For a full list of parameters, see [PluralRulesOptions](../reference/apis/js-apis-intl.md#pluralrulesoptions8). + Alternatively, use your own locale and formatting parameters to create a **PluralRules** object. For a full list of parameters, see [PluralRulesOptions](../reference/apis/js-apis-intl.md#pluralrulesoptions9). ```js var pluralRules = new intl.PluralRules("zh-CN", {localeMatcher: "best fit", type: "cardinal"}); @@ -287,13 +287,13 @@ Use [RelativeTimeFormat](../reference/apis/js-apis-intl.md#relativetimeformat8) ### Available APIs -| Module | API | Description | +| Module | API | Description | | -------- | -------- | -------- | -| ohos.intl | constructor()8+ | Creates a **RelativeTimeFormat** object. | -| ohos.intl | constructor(locale: string \| Array<string>, options?: RelativeTimeFormatInputOptions)8+ | Creates a **RelativeTimeFormat** object and sets the locale and other formatting-related attributes. | -| ohos.intl | format(value: number, unit: string): string8+ | Calculates the relative time format based on the locale and other formatting-related attributes of the **RelativeTimeFormat** object. | -| ohos.intl | formatToParts(value: number, unit: string): Array<object>8+ | Returns each part of the relative time format based on the locale and other formatting-related attributes of the **RelativeTimeFormat** object. | -| ohos.intl | resolvedOptions(): RelativeTimeFormatResolvedOptions8+ | Obtains attributes of the **RelativeTimeFormat** object. | +| ohos.intl | constructor()8+ | Creates a **RelativeTimeFormat** object. | +| ohos.intl | constructor(locale: string \| Array<string>, options?: RelativeTimeFormatInputOptions)8+ | Creates a **RelativeTimeFormat** object and sets the locale and other formatting-related attributes. | +| ohos.intl | format(value: number, unit: string): string8+ | Calculates the relative time format based on the locale and other formatting-related attributes of the **RelativeTimeFormat** object. | +| ohos.intl | formatToParts(value: number, unit: string): Array<object>8+ | Returns each part of the relative time format based on the locale and other formatting-related attributes of the **RelativeTimeFormat** object. | +| ohos.intl | resolvedOptions(): RelativeTimeFormatResolvedOptions8+ | Obtains attributes of the **RelativeTimeFormat** object. | ### How to Develop @@ -307,7 +307,7 @@ Use [RelativeTimeFormat](../reference/apis/js-apis-intl.md#relativetimeformat8) var relativeTimeFormat = new intl.RelativeTimeFormat(); ``` - Alternatively, use your own locale and formatting parameters to create a **RelativeTimeFormat** object. Formatting parameters are optional. For a full list of formatting parameters, see [RelativeTimeFormatInputOptions](../reference/apis/js-apis-intl.md#relativetimeformatinputoptions8). + Alternatively, use your own locale and formatting parameters to create a **RelativeTimeFormat** object. Formatting parameters are optional. For a full list of formatting parameters, see [RelativeTimeFormatInputOptions](../reference/apis/js-apis-intl.md#relativetimeformatinputoptions9). ```js var relativeTimeFormat = new intl.RelativeTimeFormat("zh-CN", {numeric: "always", style: "long"}); @@ -347,4 +347,4 @@ The following sample is provided to help you better understand how to develop in -[`International`: Internationalization (JS) (API8)](https://gitee.com/openharmony/applications_app_samples/tree/master/UI/International) --[`International`: Internationalization (eTS) (API8) (Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/master/common/International) +-[`International`: Internationalization (ArkTS) (API8) (Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/master/common/International) diff --git a/en/application-dev/media/Readme-EN.md b/en/application-dev/media/Readme-EN.md index 5f6e88fc07c88d3e5913058a26887e818a3cc3bc..d65c0d9dbe51f963385afaac0b75deccc6b21d2b 100755 --- a/en/application-dev/media/Readme-EN.md +++ b/en/application-dev/media/Readme-EN.md @@ -1,23 +1,29 @@ # Media -- Audio - - [Audio Overview](audio-overview.md) - - [Audio Playback Development](audio-playback.md) - - [Audio Recording Development](audio-recorder.md) - - [Audio Rendering Development](audio-renderer.md) - - [Audio Stream Management Development](audio-stream-manager.md) - - [Audio Capture Development](audio-capturer.md) - - [OpenSL ES Audio Playback Development](opensles-playback.md) - - [OpenSL ES Audio Recording Development](opensles-capture.md) - - [Audio Interruption Mode Development](audio-interruptmode.md) - -- Video - - [Video Playback Development](video-playback.md) - - [Video Recording Development](video-recorder.md) - -- Image +- Audio + - [Audio Overview](audio-overview.md) + - [Audio Playback Development](audio-playback.md) + - [Audio Recording Development](audio-recorder.md) + - [Audio Rendering Development](audio-renderer.md) + - [Audio Stream Management Development](audio-stream-manager.md) + - [Audio Capture Development](audio-capturer.md) + - [OpenSL ES Audio Playback Development](opensles-playback.md) + - [OpenSL ES Audio Recording Development](opensles-capture.md) + - [Audio Interruption Mode Development](audio-interruptmode.md) + - [Volume Management Development](audio-volume-manager.md) + - [Audio Routing and Device Management Development](audio-routing-manager.md) + +- Video + - [Video Playback Development](video-playback.md) + - [Video Recording Development](video-recorder.md) + +- AVSession + - [AVSession Overview](avsession-overview.md) + - [AVSession Development](avsession-guidelines.md) + +- Image - [Image Development](image.md) - -- Camera - - [Camera Development](camera.md) - - [Distributed Camera Development](remote-camera.md) + +- Camera + - [Camera Development](camera.md) + - [Distributed Camera Development](remote-camera.md) diff --git a/en/application-dev/media/audio-capturer.md b/en/application-dev/media/audio-capturer.md index 0815ef31a288440271a27a8f03fb417923a46190..539de6bb5c5a0723aa68a8994f7ee1970f393a3f 100644 --- a/en/application-dev/media/audio-capturer.md +++ b/en/application-dev/media/audio-capturer.md @@ -1,106 +1,101 @@ # Audio Capture Development -## When to Use +## Introduction -You can use the APIs provided by **AudioCapturer** to record raw audio files. +You can use the APIs provided by **AudioCapturer** to record raw audio files, thereby implementing audio data collection. -### State Check +**Status check**: During application development, you are advised to use **on('stateChange')** to subscribe to state changes of the **AudioCapturer** instance. This is because some operations can be performed only when the audio capturer is in a given state. If the application performs an operation when the audio capturer is not in the given state, the system may throw an exception or generate other undefined behavior. -During application development, you are advised to use **on('stateChange')** to subscribe to state changes of the **AudioCapturer** instance. This is because some operations can be performed only when the audio capturer is in a given state. If the application performs an operation when the audio capturer is not in the given state, the system may throw an exception or generate other undefined behavior. +## Working Principles -For details about the APIs, see [AudioCapturer in Audio Management](../reference/apis/js-apis-audio.md#audiocapturer8). +This following figure shows the audio capturer state transitions. + +**Figure 1** Audio capturer state transitions + +![audio-capturer-state](figures/audio-capturer-state.png) + +- **PREPARED**: The audio capturer enters this state by calling **create()**. +- **RUNNING**: The audio capturer enters this state by calling **start()** when it is in the **PREPARED** state or by calling **start()** when it is in the **STOPPED** state. +- **STOPPED**: The audio capturer in the **RUNNING** state can call **stop()** to stop playing audio data. +- **RELEASED**: The audio capturer in the **PREPARED** or **STOPPED** state can use **release()** to release all occupied hardware and software resources. It will not transit to any other state after it enters the **RELEASED** state. -**Figure 1** Audio capturer state +## Constraints -![](figures/audio-capturer-state.png) +Before developing the audio data collection feature, configure the **ohos.permission.MICROPHONE** permission for your application. For details about permission configuration, see [Permission Application Guide](../security/accesstoken-guidelines.md). ## How to Develop +For details about the APIs, see [AudioCapturer in Audio Management](../reference/apis/js-apis-audio.md#audiocapturer8). + 1. Use **createAudioCapturer()** to create an **AudioCapturer** instance. - Set parameters of the **AudioCapturer** instance in **audioCapturerOptions**. This instance is used to capture audio, control and obtain the recording status, and register a callback for notification. + Set parameters of the **AudioCapturer** instance in **audioCapturerOptions**. This instance is used to capture audio, control and obtain the recording state, and register a callback for notification. ```js - var audioStreamInfo = { - samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100, - channels: audio.AudioChannel.CHANNEL_1, - sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, - encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW - } - - var audioCapturerInfo = { - source: audio.SourceType.SOURCE_TYPE_MIC, - capturerFlags: 1 - } - - var audioCapturerOptions = { - streamInfo: audioStreamInfo, - capturerInfo: audioCapturerInfo - } - - let audioCapturer = await audio.createAudioCapturer(audioCapturerOptions); - var state = audioRenderer.state; - ``` - -2. (Optional) Use **on('stateChange')** to subscribe to audio renderer state changes. -If an application needs to perform some operations when the audio renderer state is updated, the application can subscribe to the state changes. For more events that can be subscribed to, see [Audio Management](../reference/apis/js-apis-audio.md). + import audio from '@ohos.multimedia.audio'; - ```js - audioCapturer.on('stateChange',(state) => { - console.info('AudioCapturerLog: Changed State to : ' + state) - switch (state) { - case audio.AudioState.STATE_PREPARED: - console.info('--------CHANGE IN AUDIO STATE----------PREPARED--------------'); - console.info('Audio State is : Prepared'); - break; - case audio.AudioState.STATE_RUNNING: - console.info('--------CHANGE IN AUDIO STATE----------RUNNING--------------'); - console.info('Audio State is : Running'); - break; - case audio.AudioState.STATE_STOPPED: - console.info('--------CHANGE IN AUDIO STATE----------STOPPED--------------'); - console.info('Audio State is : stopped'); - break; - case audio.AudioState.STATE_RELEASED: - console.info('--------CHANGE IN AUDIO STATE----------RELEASED--------------'); - console.info('Audio State is : released'); - break; - default: - console.info('--------CHANGE IN AUDIO STATE----------INVALID--------------'); - console.info('Audio State is : invalid'); - break; - } - }); + let audioStreamInfo = { + samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100, + channels: audio.AudioChannel.CHANNEL_1, + sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, + encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW + } + + let audioCapturerInfo = { + source: audio.SourceType.SOURCE_TYPE_MIC, + capturerFlags: 0 // 0 is the extended flag bit of the audio capturer. The default value is 0. + } + + let audioCapturerOptions = { + streamInfo: audioStreamInfo, + capturerInfo: audioCapturerInfo + } + + let audioCapturer = await audio.createAudioCapturer(audioCapturerOptions); + console.log('AudioRecLog: Create audio capturer success.'); ``` -3. Use **start()** to start audio recording. +2. Use **start()** to start audio recording. The capturer state will be **STATE_RUNNING** once the audio capturer is started. The application can then begin reading buffers. ```js - await audioCapturer.start(); - if (audioCapturer.state == audio.AudioState.STATE_RUNNING) { - console.info('AudioRecLog: Capturer started'); - } else { - console.info('AudioRecLog: Capturer start failed'); - } - ``` - -4. Use **getBufferSize()** to obtain the minimum buffer size to read. + import audio from '@ohos.multimedia.audio'; + + async function startCapturer() { + let state = audioCapturer.state; + // The audio capturer should be in the STATE_PREPARED, STATE_PAUSED, or STATE_STOPPED state after being started. + if (state != audio.AudioState.STATE_PREPARED || state != audio.AudioState.STATE_PAUSED || + state != audio.AudioState.STATE_STOPPED) { + console.info('Capturer is not in a correct state to start'); + return; + } + await audioCapturer.start(); - ```js - var bufferSize = await audioCapturer.getBufferSize(); - console.info('AudioRecLog: buffer size: ' + bufferSize); + let state = audioCapturer.state; + if (state == audio.AudioState.STATE_RUNNING) { + console.info('AudioRecLog: Capturer started'); + } else { + console.error('AudioRecLog: Capturer start failed'); + } + } ``` -5. Read the captured audio data and convert it to a byte stream. Call **read()** repeatedly to read the data until the application wants to stop the recording. +3. Read the captured audio data and convert it to a byte stream. Call **read()** repeatedly to read the data until the application stops the recording. The following example shows how to write recorded data into a file. ```js import fileio from '@ohos.fileio'; + + let state = audioCapturer.state; + // The read operation can be performed only when the state is STATE_RUNNING. + if (state != audio.AudioState.STATE_RUNNING) { + console.info('Capturer is not in a correct state to read'); + return; + } - const path = '/data/data/.pulse_dir/capture_js.wav'; + const path = '/data/data/.pulse_dir/capture_js.wav'; // Path for storing the collected audio file. let fd = fileio.openSync(path, 0o102, 0o777); if (fd !== null) { console.info('AudioRecLog: file fd created'); @@ -115,38 +110,140 @@ If an application needs to perform some operations when the audio renderer state console.info('AudioRecLog: file fd opened in append mode'); } - var numBuffersToCapture = 150; + let numBuffersToCapture = 150; // Write data for 150 times. while (numBuffersToCapture) { - var buffer = await audioCapturer.read(bufferSize, true); + let buffer = await audioCapturer.read(bufferSize, true); if (typeof(buffer) == undefined) { - console.info('read buffer failed'); + console.info('AudioRecLog: read buffer failed'); } else { - var number = fileio.writeSync(fd, buffer); - console.info('AudioRecLog: data written: ' + number); + let number = fileio.writeSync(fd, buffer); + console.info(`AudioRecLog: data written: ${number}`); } numBuffersToCapture--; } ``` -6. Once the recording is complete, call **stop()** to stop the recording. +4. Once the recording is complete, call **stop()** to stop the recording. + ```js + async function StopCapturer() { + let state = audioCapturer.state; + // The audio capturer can be stopped only when it is in STATE_RUNNING or STATE_PAUSED state. + if (state != audio.AudioState.STATE_RUNNING && state != audio.AudioState.STATE_PAUSED) { + console.info('AudioRecLog: Capturer is not running or paused'); + return; + } + + await audioCapturer.stop(); + + state = audioCapturer.state; + if (state == audio.AudioState.STATE_STOPPED) { + console.info('AudioRecLog: Capturer stopped'); + } else { + console.error('AudioRecLog: Capturer stop failed'); + } + } ``` - await audioCapturer.stop(); - if (audioCapturer.state == audio.AudioState.STATE_STOPPED) { - console.info('AudioRecLog: Capturer stopped'); - } else { - console.info('AudioRecLog: Capturer stop failed'); - } + +5. After the task is complete, call **release()** to release related resources. + + ```js + async function releaseCapturer() { + let state = audioCapturer.state; + // The audio capturer can be released only when it is not in the STATE_RELEASED or STATE_NEW state. + if (state == audio.AudioState.STATE_RELEASED || state == audio.AudioState.STATE_NEW) { + console.info('AudioRecLog: Capturer already released'); + return; + } + + await audioCapturer.release(); + + state = audioCapturer.state; + if (state == audio.AudioState.STATE_RELEASED) { + console.info('AudioRecLog: Capturer released'); + } else { + console.info('AudioRecLog: Capturer release failed'); + } + } ``` -7. After the task is complete, call **release()** to release related resources. +6. (Optional) Obtain the audio capturer information. + + You can use the following code to obtain the audio capturer information: ```js - await audioCapturer.release(); - if (audioCapturer.state == audio.AudioState.STATE_RELEASED) { - console.info('AudioRecLog: Capturer released'); - } else { - console.info('AudioRecLog: Capturer release failed'); - } + // Obtain the audio capturer state. + let state = audioCapturer.state; + + // Obtain the audio capturer information. + let audioCapturerInfo : audio.AuduioCapturerInfo = await audioCapturer.getCapturerInfo(); + + // Obtain the audio stream information. + let audioStreamInfo : audio.AudioStreamInfo = await audioCapturer.getStreamInfo(); + + // Obtain the audio stream ID. + let audioStreamId : number = await audioCapturer.getAudioStreamId(); + + // Obtain the Unix timestamp, in nanoseconds. + let audioTime : number = await audioCapturer.getAudioTime(); + + // Obtain a proper minimum buffer size. + let bufferSize : number = await audioCapturer.getBuffersize(); ``` + +7. (Optional) Use **on('markReach')** to subscribe to the mark reached event, and use **off('markReach')** to unsubscribe from the event. + + After the mark reached event is subscribed to, when the number of frames collected by the audio capturer reaches the specified value, a callback is triggered and the specified value is returned. + + ```js + audioCapturer.on('markReach', (reachNumber) => { + console.info('Mark reach event Received'); + console.info(`The Capturer reached frame: ${reachNumber}`); + }); + + audioCapturer.off('markReach'); // Unsubscribe from the mark reached event. This event will no longer be listened for. + ``` + +8. (Optional) Use **on('periodReach')** to subscribe to the period reached event, and use **off('periodReach')** to unsubscribe from the event. + + After the period reached event is subscribed to, each time the number of frames collected by the audio capturer reaches the specified value, a callback is triggered and the specified value is returned. + + ```js + audioCapturer.on('periodReach', (reachNumber) => { + console.info('Period reach event Received'); + console.info(`In this period, the Capturer reached frame: ${reachNumber}`); + }); + + audioCapturer.off('periodReach'); // Unsubscribe from the period reached event. This event will no longer be listened for. + ``` + +9. If your application needs to perform some operations when the audio capturer state is updated, it can subscribe to the state change event. When the audio capturer state is updated, the application receives a callback containing the event type. + + ```js + audioCapturer.on('stateChange', (state) => { + console.info(`AudioCapturerLog: Changed State to : ${state}`) + switch (state) { + case audio.AudioState.STATE_PREPARED: + console.info('--------CHANGE IN AUDIO STATE----------PREPARED--------------'); + console.info('Audio State is : Prepared'); + break; + case audio.AudioState.STATE_RUNNING: + console.info('--------CHANGE IN AUDIO STATE----------RUNNING--------------'); + console.info('Audio State is : Running'); + break; + case audio.AudioState.STATE_STOPPED: + console.info('--------CHANGE IN AUDIO STATE----------STOPPED--------------'); + console.info('Audio State is : stopped'); + break; + case audio.AudioState.STATE_RELEASED: + console.info('--------CHANGE IN AUDIO STATE----------RELEASED--------------'); + console.info('Audio State is : released'); + break; + default: + console.info('--------CHANGE IN AUDIO STATE----------INVALID--------------'); + console.info('Audio State is : invalid'); + break; + } + }); + ``` diff --git a/en/application-dev/media/audio-interruptmode.md b/en/application-dev/media/audio-interruptmode.md index 8be8a00cedd10ff4ecd08ee46d746d9803b3c71a..48a53bf5d5990ac88aae1271466a6aa36d52ac98 100644 --- a/en/application-dev/media/audio-interruptmode.md +++ b/en/application-dev/media/audio-interruptmode.md @@ -1,49 +1,50 @@ # Audio Interruption Mode Development -## When to Use -The audio interruption mode is used to control the playback of multiple audio streams.
-Audio applications can set the audio interruption mode to independent or shared under **AudioRenderer**.
-In shared mode, multiple audio streams share one session ID. In independent mode, each audio stream has an independent session ID. +## Introduction +The audio interruption mode is used to control the playback of multiple audio streams. + +Audio applications can set the audio interruption mode to independent or shared under **AudioRenderer**. -### Asynchronous Operations +In shared mode, multiple audio streams share one session ID. In independent mode, each audio stream has an independent session ID. -To prevent the UI thread from being blocked, most **AudioRenderer** calls are asynchronous. Each API provides the callback and promise functions. The following examples use the promise functions. +**Asynchronous operation**: To prevent the UI thread from being blocked, most **AudioRenderer** calls are asynchronous. Each API provides the callback and promise functions. The following examples use the promise functions. ## How to Develop For details about the APIs, see [AudioRenderer in Audio Management](../reference/apis/js-apis-audio.md#audiorenderer8). +1. Use **createAudioRenderer()** to create an **AudioRenderer** instance. + + Set parameters of the **AudioRenderer** instance in **audioRendererOptions**. -1. Use **createAudioRenderer()** to create an **AudioRenderer** instance.
- Set parameters of the **AudioRenderer** instance in **audioRendererOptions**.
- This instance is used to render audio, control and obtain the rendering status, and register a callback for notification.
- - ```js + This instance is used to render audio, control and obtain the rendering status, and register a callback for notification. + +```js import audio from '@ohos.multimedia.audio'; - - var audioStreamInfo = { - samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100, - channels: audio.AudioChannel.CHANNEL_1, - sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, - encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW - } - var audioRendererInfo = { - content: audio.ContentType.CONTENT_TYPE_SPEECH, - usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION, - rendererFlags: 1 - } + var audioStreamInfo = { + samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100, + channels: audio.AudioChannel.CHANNEL_1, + sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, + encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW + } + + var audioRendererInfo = { + content: audio.ContentType.CONTENT_TYPE_SPEECH, + usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION, + rendererFlags: 1 + } - var audioRendererOptions = { - streamInfo: audioStreamInfo, - rendererInfo: audioRendererInfo - } + var audioRendererOptions = { + streamInfo: audioStreamInfo, + rendererInfo: audioRendererInfo + } - let audioRenderer = await audio.createAudioRenderer(audioRendererOptions); +let audioRenderer = await audio.createAudioRenderer(audioRendererOptions); ``` - -2. Set the audio interruption mode. +2. Set the audio interruption mode. + After the **AudioRenderer** instance is initialized, you can set the audio interruption mode.
```js diff --git a/en/application-dev/media/audio-playback.md b/en/application-dev/media/audio-playback.md index 5227f6cdd1b9ec89818b0d1762c99267ec7eba97..bbdb993ecdb9a1289a939af43db0e670ec10f98f 100644 --- a/en/application-dev/media/audio-playback.md +++ b/en/application-dev/media/audio-playback.md @@ -1,25 +1,35 @@ # Audio Playback Development -## When to Use +## Introduction -You can use audio playback APIs to convert audio data into audible analog signals, play the signals using output devices, and manage playback tasks. +You can use audio playback APIs to convert audio data into audible analog signals and play the signals using output devices. You can also manage playback tasks. For example, you can control the playback and volume, obtain track information, and release resources. -**Figure 1** Playback status +## Working Principles + +The following figures show the audio playback state transition and the interaction with external modules for audio playback. + +**Figure 1** Audio playback state transition ![en-us_image_audio_state_machine](figures/en-us_image_audio_state_machine.png) -**Note**: If the status is **Idle**, setting the **src** attribute does not change the status. In addition, after the **src** attribute is set successfully, you must call **reset()** before setting it to another value. +**NOTE**: If the status is **Idle**, setting the **src** attribute does not change the status. In addition, after the **src** attribute is set successfully, you must call **reset()** before setting it to another value. -**Figure 2** Layer 0 diagram of audio playback +**Figure 2** Interaction with external modules for audio playback ![en-us_image_audio_player](figures/en-us_image_audio_player.png) +**NOTE**: When a third-party application calls the JS interface provided by the JS interface layer to implement a feature, the framework layer invokes the audio component through the media service of the native framework and outputs the audio data decoded by the software to the audio HDI of the hardware interface layer to implement audio playback. + ## How to Develop For details about the APIs, see [AudioPlayer in the Media API](../reference/apis/js-apis-media.md#audioplayer). +> **NOTE** +> +> The method for obtaining the path in the FA model is different from that in the stage model. For details about how to obtain the path, see [Application Sandbox Path Guidelines](../reference/apis/js-apis-fileio.md#guidelines). + ### Full-Process Scenario The full audio playback process includes creating an instance, setting the URI, playing audio, seeking to the playback position, setting the volume, pausing playback, obtaining track information, stopping playback, resetting the player, and releasing resources. @@ -99,8 +109,9 @@ async function audioPlayerDemo() { setCallBack(audioPlayer); // Set the event callbacks. // 2. Set the URI of the audio file. let fdPath = 'fd://' - // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\01.mp3 /data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile" command. - let path = '/data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile/01.mp3'; + let pathDir = "/data/storage/el2/base/haps/entry/files" // The path used here is an example. Obtain the path based on project requirements. + // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\01.mp3 /data/app/el2/100/base/ohos.acts.multimedia.audio.audioplayer/haps/entry/files" command. + let path = pathDir + '/01.mp3' await fileIO.open(path).then((fdNumber) => { fdPath = fdPath + '' + fdNumber; console.info('open fd success fd is' + fdPath); @@ -118,6 +129,7 @@ async function audioPlayerDemo() { ```js import media from '@ohos.multimedia.media' import fileIO from '@ohos.fileio' + export class AudioDemo { // Set the player callbacks. setCallBack(audioPlayer) { @@ -139,8 +151,9 @@ export class AudioDemo { let audioPlayer = media.createAudioPlayer(); // Create an AudioPlayer instance. this.setCallBack(audioPlayer); // Set the event callbacks. let fdPath = 'fd://' - // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\01.mp3 /data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile" command. - let path = '/data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile/01.mp3'; + let pathDir = "/data/storage/el2/base/haps/entry/files" // The path used here is an example. Obtain the path based on project requirements. + // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\01.mp3 /data/app/el2/100/base/ohos.acts.multimedia.audio.audioplayer/haps/entry/files" command. + let path = pathDir + '/01.mp3' await fileIO.open(path).then((fdNumber) => { fdPath = fdPath + '' + fdNumber; console.info('open fd success fd is' + fdPath); @@ -159,6 +172,7 @@ export class AudioDemo { ```js import media from '@ohos.multimedia.media' import fileIO from '@ohos.fileio' + export class AudioDemo { // Set the player callbacks. private isNextMusic = false; @@ -185,8 +199,9 @@ export class AudioDemo { async nextMusic(audioPlayer) { this.isNextMusic = true; let nextFdPath = 'fd://' - // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\02.mp3 /data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile" command. - let nextpath = '/data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile/02.mp3'; + let pathDir = "/data/storage/el2/base/haps/entry/files" // The path used here is an example. Obtain the path based on project requirements. + // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\02.mp3 /data/app/el2/100/base/ohos.acts.multimedia.audio.audioplayer/haps/entry/files" command. + let nextpath = pathDir + '/02.mp3' await fileIO.open(nextpath).then((fdNumber) => { nextFdPath = nextFdPath + '' + fdNumber; console.info('open fd success fd is' + nextFdPath); @@ -202,8 +217,9 @@ export class AudioDemo { let audioPlayer = media.createAudioPlayer(); // Create an AudioPlayer instance. this.setCallBack(audioPlayer); // Set the event callbacks. let fdPath = 'fd://' - // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\01.mp3 /data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile" command. - let path = '/data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile/01.mp3'; + let pathDir = "/data/storage/el2/base/haps/entry/files" // The path used here is an example. Obtain the path based on project requirements. + // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\01.mp3 /data/app/el2/100/base/ohos.acts.multimedia.audio.audioplayer/haps/entry/files" command. + let path = pathDir + '/01.mp3' await fileIO.open(path).then((fdNumber) => { fdPath = fdPath + '' + fdNumber; console.info('open fd success fd is' + fdPath); @@ -222,6 +238,7 @@ export class AudioDemo { ```js import media from '@ohos.multimedia.media' import fileIO from '@ohos.fileio' + export class AudioDemo { // Set the player callbacks. setCallBack(audioPlayer) { @@ -239,8 +256,9 @@ export class AudioDemo { let audioPlayer = media.createAudioPlayer(); // Create an AudioPlayer instance. this.setCallBack(audioPlayer); // Set the event callbacks. let fdPath = 'fd://' - // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\01.mp3 /data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile" command. - let path = '/data/app/el1/bundle/public/ohos.acts.multimedia.audio.audioplayer/ohos.acts.multimedia.audio.audioplayer/assets/entry/resources/rawfile/01.mp3'; + let pathDir = "/data/storage/el2/base/haps/entry/files" // The path used here is an example. Obtain the path based on project requirements. + // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\01.mp3 /data/app/el2/100/base/ohos.acts.multimedia.audio.audioplayer/haps/entry/files" command. + let path = pathDir + '/01.mp3' await fileIO.open(path).then((fdNumber) => { fdPath = fdPath + '' + fdNumber; console.info('open fd success fd is' + fdPath); diff --git a/en/application-dev/media/audio-recorder.md b/en/application-dev/media/audio-recorder.md index f465db2b88118b77c9a4e64307170da07c3e8918..78650a61d0a803811394e623ab0bc46155438ba9 100644 --- a/en/application-dev/media/audio-recorder.md +++ b/en/application-dev/media/audio-recorder.md @@ -1,8 +1,12 @@ # Audio Recording Development -## When to Use +## Introduction -During audio recording, audio signals are captured, encoded, and saved to files. You can specify parameters such as the sampling rate, number of audio channels, encoding format, encapsulation format, and file path for audio recording. +During audio recording, audio signals are captured, encoded, and saved to files. You can specify parameters such as the sampling rate, number of audio channels, encoding format, encapsulation format, and output file path for audio recording. + +## Working Principles + +The following figures show the audio recording state transition and the interaction with external modules for audio recording. **Figure 1** Audio recording state transition @@ -10,10 +14,16 @@ During audio recording, audio signals are captured, encoded, and saved to files. -**Figure 2** Layer 0 diagram of audio recording +**Figure 2** Interaction with external modules for audio recording ![en-us_image_audio_recorder_zero](figures/en-us_image_audio_recorder_zero.png) +**NOTE**: When a third-party recording application or recorder calls the JS interface provided by the JS interface layer to implement a feature, the framework layer invokes the audio component through the media service of the native framework to obtain the audio data captured through the audio HDI. The framework layer then encodes the audio data through software and saves the encoded and encapsulated audio data to a file to implement audio recording. + +## Constraints + +Before developing audio recording, configure the **ohos.permission.MICROPHONE** permission for your application. For details about the configuration, see [Permission Application Guide](../security/accesstoken-guidelines.md). + ## How to Develop For details about the APIs, see [AudioRecorder in the Media API](../reference/apis/js-apis-media.md#audiorecorder). diff --git a/en/application-dev/media/audio-renderer.md b/en/application-dev/media/audio-renderer.md index 82a0753b66384e6f1a991ba97f7d6c7580936e0e..699eb7cb6cae5f198c1620e22b7c3f0df4a90813 100644 --- a/en/application-dev/media/audio-renderer.md +++ b/en/application-dev/media/audio-renderer.md @@ -1,214 +1,197 @@ # Audio Rendering Development -## When to Use +## Introduction **AudioRenderer** provides APIs for rendering audio files and controlling playback. It also supports audio interruption. You can use the APIs provided by **AudioRenderer** to play audio files in output devices and manage playback tasks. -### Audio Interruption +Before calling the APIs, be familiar with the following terms: -When an audio stream with a higher priority needs to be played, the audio renderer interrupts the stream with a lower priority. For example, if a call comes in when the user is listening to music, the music playback, which is the lower priority stream, is paused. For details, see [How to Develop](#how-to-develop). +- **Audio interruption**: When an audio stream with a higher priority needs to be played, the audio renderer interrupts the stream with a lower priority. For example, if a call comes in when the user is listening to music, the music playback, which is the lower priority stream, is paused. +- **Status check**: During application development, you are advised to use **on('stateChange')** to subscribe to state changes of the **AudioRenderer** instance. This is because some operations can be performed only when the audio renderer is in a given state. If the application performs an operation when the audio renderer is not in the given state, the system may throw an exception or generate other undefined behavior. +- **Asynchronous operation**: To prevent the UI thread from being blocked, most **AudioRenderer** calls are asynchronous. Each API provides the callback and promise functions. The following examples use the promise functions. For more information, see [AudioRenderer in Audio Management](../reference/apis/js-apis-audio.md#audiorenderer8). +- **Audio interruption mode**: OpenHarmony provides two audio interruption modes: **shared mode** and **independent mode**. In shared mode, all **AudioRenderer** instances created by the same application share one focus object, and there is no focus transfer inside the application. Therefore, no callback will be triggered. In independent mode, each **AudioRenderer** instance has an independent focus object, and focus preemption occurs. Focus preemption triggers focus transfer, and the **AudioRenderer** instance that originally has the focus receives a notification through the callback. By default, the shared mode is used. You can call **setInterruptMode()** to set the independent mode. -### State Check +## Working Principles -During application development, you are advised to use **on('stateChange')** to subscribe to state changes of the **AudioRenderer** instance. This is because some operations can be performed only when the audio renderer is in a given state. If the application performs an operation when the audio renderer is not in the given state, the system may throw an exception or generate other undefined behavior. +The following figure shows the audio renderer state transitions. -**Figure 1** Audio renderer state +Figure 1 Audio renderer state transitions -![](figures/audio-renderer-state.png) +![audio-renderer-state](figures/audio-renderer-state.png) -### Asynchronous Operations - -To ensure that the UI thread is not blocked, most **AudioRenderer** calls are asynchronous. Each API provides the callback and promise functions. The following examples use the promise functions. For more information, see [AudioRenderer in Audio Management](../reference/apis/js-apis-audio.md#audiorenderer8). +- **PREPARED**: The audio renderer enters this state by calling **create()**. +- **RUNNING**: The audio renderer enters this state by calling **start()** when it is in the **PREPARED** state or by calling **start()** when it is in the **STOPPED** state. +- **PAUSED**: The audio renderer in the **RUNNING** state can call **pause()** to pause the audio playback. After the audio playback is paused, it can call **start()** to resume the playback. +- **STOPPED**: The audio renderer in the **PAUSED** or **RUNNING** state can call **stop()** to stop the playback. +- **RELEASED**: The audio renderer in the **PREPARED**, **PAUSED**, or **STOPPED** state can use **release()** to release all occupied hardware and software resources. It will not transit to any other state after it enters the **RELEASED** state. ## How to Develop +For details about the APIs, see [AudioRenderer in Audio Management](../reference/apis/js-apis-audio.md#audiorenderer8). + 1. Use **createAudioRenderer()** to create an **AudioRenderer** instance. - Set parameters of the audio renderer in **audioCapturerOptions**. This instance is used to render audio, control and obtain the rendering status, and register a callback for notification. + + +Set parameters of the **AudioRenderer** instance in **audioRendererOptions**. This instance is used to render audio, control and obtain the rendering status, and register a callback for notification. ```js - var audioStreamInfo = { + import audio from '@ohos.multimedia.audio'; + + let audioStreamInfo = { samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100, channels: audio.AudioChannel.CHANNEL_1, sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW } - - var audioRendererInfo = { + let audioRendererInfo = { content: audio.ContentType.CONTENT_TYPE_SPEECH, usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION, - rendererFlags: 1 + rendererFlags: 0 // 0 is the extended flag bit of the audio renderer. The default value is 0. } - - var audioRendererOptions = { + let audioRendererOptions = { streamInfo: audioStreamInfo, rendererInfo: audioRendererInfo - } + } let audioRenderer = await audio.createAudioRenderer(audioRendererOptions); + console.log("Create audio renderer success."); ``` -2. Use **on('interrupt')** to subscribe to audio interruption events. - - Stream-A is interrupted when Stream-B with a higher or equal priority requests to become active and use the output device. - - In some cases, the audio renderer performs forcible operations such as pausing and ducking, and notifies the application through **InterruptEvent**. In other cases, the application can choose to act on the **InterruptEvent** or ignore it. +2. Use **start()** to start audio rendering. - In the case of audio interruption, the application may encounter write failures. To avoid such failures, interruption unaware applications can use **audioRenderer.state** to check the renderer state before writing audio data. The applications can obtain more details by subscribing to the audio interruption events. For details, see [InterruptEvent](../reference/apis/js-apis-audio.md#interruptevent9). - ```js - audioRenderer.on('interrupt', (interruptEvent) => { - console.info('InterruptEvent Received'); - console.info('InterruptType: ' + interruptEvent.eventType); - console.info('InterruptForceType: ' + interruptEvent.forceType); - console.info('AInterruptHint: ' + interruptEvent.hintType); + async function startRenderer() { + let state = audioRenderer.state; + // The audio renderer should be in the STATE_PREPARED, STATE_PAUSED, or STATE_STOPPED state after being started. + if (state != audio.AudioState.STATE_PREPARED && state != audio.AudioState.STATE_PAUSED && + state != audio.AudioState.STATE_STOPPED) { + console.info('Renderer is not in a correct state to start'); + return; + } - if (interruptEvent.forceType == audio.InterruptForceType.INTERRUPT_FORCE) { - switch (interruptEvent.hintType) { - // Force Pause: Action was taken by framework. - // Halt the write calls to avoid data loss. - case audio.InterruptHint.INTERRUPT_HINT_PAUSE: - isPlay = false; - break; - // Force Stop: Action was taken by framework. - // Halt the write calls to avoid data loss. - case audio.InterruptHint.INTERRUPT_HINT_STOP: - isPlay = false; - break; - // Force Duck: Action was taken by framework, - // just notifying the app that volume has been reduced. - case audio.InterruptHint.INTERRUPT_HINT_DUCK: - break; - // Force Unduck: Action was taken by framework, - // just notifying the app that volume has been restored. - case audio.InterruptHint.INTERRUPT_HINT_UNDUCK: - break; - } - } else if (interruptEvent.forceType == audio.InterruptForceType.INTERRUPT_SHARE) { - switch (interruptEvent.hintType) { - // Share Resume: Action is to be taken by App. - // Resume the force paused stream if required. - case audio.InterruptHint.INTERRUPT_HINT_RESUME: - startRenderer(); - break; - // Share Pause: Stream has been interrupted, - // It can choose to pause or play concurrently. - case audio.InterruptHint.INTERRUPT_HINT_PAUSE: - isPlay = false; - pauseRenderer(); - break; - } - } - }); - ``` - -3. Use **start()** to start audio rendering. + await audioRenderer.start(); + state = audioRenderer.state; + if (state == audio.AudioState.STATE_RUNNING) { + console.info('Renderer started'); + } else { + console.error('Renderer start failed'); + } + } + ``` The renderer state will be **STATE_RUNNING** once the audio renderer is started. The application can then begin reading buffers. - ```js - async function startRenderer() { - var state = audioRenderer.state; - // The state should be prepared, paused, or stopped. - if (state != audio.AudioState.STATE_PREPARED || state != audio.AudioState.STATE_PAUSED || - state != audio.AudioState.STATE_STOPPED) { - console.info('Renderer is not in a correct state to start'); - return; - } - - await audioRenderer.start(); - - state = audioRenderer.state; - if (state == audio.AudioState.STATE_RUNNING) { - console.info('Renderer started'); - } else { - console.error('Renderer start failed'); - } - } - ``` -4. Call **write()** to write data to the buffer. +3. Call **write()** to write data to the buffer. Read the audio data to be played to the buffer. Call **write()** repeatedly to write the data to the buffer. ```js - async function writeBuffer(buf) { - var state = audioRenderer.state; - if (state != audio.AudioState.STATE_RUNNING) { - console.error('Renderer is not running, do not write'); - isPlay = false; - return; - } - let writtenbytes = await audioRenderer.write(buf); - - console.info('Actual written bytes: ' + writtenbytes); - if (writtenbytes < 0) { - console.error('Write buffer failed. check the state of renderer'); - } - } - - // Reasonable minimum buffer size for renderer. However, the renderer can accept other read sizes as well. - const bufferSize = await audioRenderer.getBufferSize(); - const path = '/data/file_example_WAV_2MG.wav'; - let ss = fileio.createStreamSync(path, 'r'); - const totalSize = 2146166; // file_example_WAV_2MG.wav - let rlen = 0; - let discardHeader = new ArrayBuffer(44); - ss.readSync(discardHeader); - rlen += 44; - - var id = setInterval(() => { - if (isPlay || isRelease) { - if (rlen >= totalSize || isRelease) { - ss.closeSync(); - stopRenderer(); - clearInterval(id); - } - let buf = new ArrayBuffer(bufferSize); - rlen += ss.readSync(buf); - console.info('Total bytes read from file: ' + rlen); - writeBuffer(buf); - } else { - console.info('check after next interval'); - } - } , 30); // interval to be set based on audio file format + import fileio from '@ohos.fileio'; + import audio from '@ohos.multimedia.audio'; + + async function writeBuffer(buf) { + // The write operation can be performed only when the state is STATE_RUNNING. + if (audioRenderer.state != audio.AudioState.STATE_RUNNING) { + console.error('Renderer is not running, do not write'); + return; + } + let writtenbytes = await audioRenderer.write(buf); + console.info(`Actual written bytes: ${writtenbytes} `); + if (writtenbytes < 0) { + console.error('Write buffer failed. check the state of renderer'); + } + } + + // Set a proper buffer size for the audio renderer. You can also select a buffer of another size. + const bufferSize = await audioRenderer.getBufferSize(); + let dir = globalThis.fileDir; // You must use the sandbox path. + const path = dir + '/file_example_WAV_2MG.wav'; // The file to render is in the following path: /data/storage/el2/base/haps/entry/files/file_example_WAV_2MG.wav + console.info(`file path: ${ path}`); + let ss = fileio.createStreamSync(path, 'r'); + const totalSize = fileio.statSync(path).size; // Size of the file to render. + let discardHeader = new ArrayBuffer(bufferSize); + ss.readSync(discardHeader); + let rlen = 0; + rlen += bufferSize; + + let id = setInterval(() => { + if (audioRenderer.state == audio.AudioState.STATE_RELEASED) { // The rendering stops if the audio renderer is in the STATE_RELEASED state. + ss.closeSync(); + await audioRenderer.stop(); + clearInterval(id); + } + if (audioRenderer.state == audio.AudioState.STATE_RUNNING) { + if (rlen >= totalSize) { // The rendering stops if the file finishes reading. + ss.closeSync(); + await audioRenderer.stop(); + clearInterval(id); + } + let buf = new ArrayBuffer(bufferSize); + rlen += ss.readSync(buf); + console.info(`Total bytes read from file: ${rlen}`); + writeBuffer(buf); + } else { + console.info('check after next interval'); + } + }, 30); // The timer interval is set based on the audio format. The unit is millisecond. ``` -5. (Optional) Call **pause()** or **stop()** to pause or stop rendering. +4. (Optional) Call **pause()** or **stop()** to pause or stop rendering. ```js async function pauseRenderer() { - var state = audioRenderer.state; - if (state != audio.AudioState.STATE_RUNNING) { - console.info('Renderer is not running'); - return; - } - - await audioRenderer.pause(); - - state = audioRenderer.state; - if (state == audio.AudioState.STATE_PAUSED) { - console.info('Renderer paused'); - } else { - console.error('Renderer pause failed'); - } + let state = audioRenderer.state; + // The audio renderer can be paused only when it is in the STATE_RUNNING state. + if (state != audio.AudioState.STATE_RUNNING) { + console.info('Renderer is not running'); + return; + } + + await audioRenderer.pause(); + + state = audioRenderer.state; + if (state == audio.AudioState.STATE_PAUSED) { + console.info('Renderer paused'); + } else { + console.error('Renderer pause failed'); + } } - + async function stopRenderer() { - var state = audioRenderer.state; - if (state != audio.AudioState.STATE_RUNNING || state != audio.AudioState.STATE_PAUSED) { - console.info('Renderer is not running or paused'); - return; - } - - await audioRenderer.stop(); - - state = audioRenderer.state; - if (state == audio.AudioState.STATE_STOPPED) { - console.info('Renderer stopped'); - } else { - console.error('Renderer stop failed'); - } - } + let state = audioRenderer.state; + // The audio renderer can be stopped only when it is in STATE_RUNNING or STATE_PAUSED state. + if (state != audio.AudioState.STATE_RUNNING && state != audio.AudioState.STATE_PAUSED) { + console.info('Renderer is not running or paused'); + return; + } + + await audioRenderer.stop(); + + state = audioRenderer.state; + if (state == audio.AudioState.STATE_STOPPED) { + console.info('Renderer stopped'); + } else { + console.error('Renderer stop failed'); + } + } + ``` + +5. (Optional) Call **drain()** to clear the buffer. + + ```js + async function drainRenderer() { + let state = audioRenderer.state; + // drain() can be used only when the audio renderer is in the STATE_RUNNING state. + if (state != audio.AudioState.STATE_RUNNING) { + console.info('Renderer is not running'); + return; + } + + await audioRenderer.drain(); + + state = audioRenderer.state; + } ``` 6. After the task is complete, call **release()** to release related resources. @@ -217,19 +200,349 @@ To ensure that the UI thread is not blocked, most **AudioRenderer** calls are as ```js async function releaseRenderer() { - if (state_ == RELEASED || state_ == NEW) { - console.info('Resourced already released'); - return; - } + let state = audioRenderer.state; + // The audio renderer can be released only when it is not in the STATE_RELEASED or STATE_NEW state. + if (state == audio.AudioState.STATE_RELEASED || state == audio.AudioState.STATE_NEW) { + console.info('Renderer already released'); + return; + } + + await audioRenderer.release(); + + state = audioRenderer.state; + if (state == audio.AudioState.STATE_RELEASED) { + console.info('Renderer released'); + } else { + console.info('Renderer release failed'); + } + } + ``` - await audioRenderer.release(); +7. (Optional) Obtain the audio renderer information. + + You can use the following code to obtain the audio renderer information: - state = audioRenderer.state; - if (state == STATE_RELEASED) { - console.info('Renderer released'); - } else { - console.info('Renderer release failed'); - } + ```js + // Obtain the audio renderer state. + let state = audioRenderer.state; + + // Obtain the audio renderer information. + let audioRendererInfo : audio.AudioRendererInfo = await audioRenderer.getRendererInfo(); - } + // Obtain the audio stream information. + let audioStreamInfo : audio.AudioStreamInfo = await audioRenderer.getStreamInfo(); + + // Obtain the audio stream ID. + let audioStreamId : number = await audioRenderer.getAudioStreamId(); + + // Obtain the Unix timestamp, in nanoseconds. + let audioTime : number = await audioRenderer.getAudioTime(); + + // Obtain a proper minimum buffer size. + let bufferSize : number = await audioRenderer.getBuffersize(); + + // Obtain the audio renderer rate. + let renderRate : audio.AudioRendererRate = await audioRenderer.getRenderRate(); ``` + +8. (Optional) Set the audio renderer information. + + You can use the following code to set the audio renderer information: + + ```js + // Set the audio renderer rate to RENDER_RATE_NORMAL. + let renderRate : audio.AudioRendererRate = audio.AudioRendererRate.RENDER_RATE_NORMAL; + await audioRenderer.setRenderRate(renderRate); + + // Set the interruption mode of the audio renderer to SHARE_MODE. + let interruptMode : audio.InterruptMode = audio.InterruptMode.SHARE_MODE; + await audioRenderer.setInterruptMode(interruptMode); + + // Set the volume of the stream to 10. + let volume : number = 10; + await audioRenderer.setVolume(volume); + ``` + +9. (Optional) Use **on('audioInterrupt')** to subscribe to the audio interruption event, and use **off('audioInterrupt')** to unsubscribe from the event. + + Audio interruption means that Stream A will be interrupted when Stream B with a higher or equal priority requests to become active and use the output device. + + In some cases, the audio renderer performs forcible operations such as pausing and ducking, and notifies the application through **InterruptEvent**. In other cases, the application can choose to act on the **InterruptEvent** or ignore it. + + In the case of audio interruption, the application may encounter write failures. To avoid such failures, interruption-unaware applications can use **audioRenderer.state** to check the audio renderer state before writing audio data. The applications can obtain more details by subscribing to the audio interruption events. For details, see [InterruptEvent](../reference/apis/js-apis-audio.md#interruptevent9). + + It should be noted that the audio interruption event subscription of the **AudioRenderer** module is slightly different from **on('interrupt')** in [AudioManager](../reference/apis/js-apis-audio.md#audiomanager). The **on('interrupt')** and **off('interrupt')** APIs are deprecated since API version 9. In the **AudioRenderer** module, you only need to call **on('audioInterrupt')** to listen for focus change events. When the **AudioRenderer** instance created by the application performs actions such as start, stop, and pause, it requests the focus, which triggers focus transfer and in return enables the related **AudioRenderer** instance to receive a notification through the callback. For instances other than **AudioRenderer**, such as frequency modulation (FM) and voice wakeup, the application does not create an instance. In this case, the application can call **on('interrupt')** in **AudioManager** to receive a focus change notification. + + ```js + audioRenderer.on('audioInterrupt', (interruptEvent) => { + console.info('InterruptEvent Received'); + console.info(`InterruptType: ${interruptEvent.eventType}`); + console.info(`InterruptForceType: ${interruptEvent.forceType}`); + console.info(`AInterruptHint: ${interruptEvent.hintType}`); + + if (interruptEvent.forceType == audio.InterruptForceType.INTERRUPT_FORCE) { + switch (interruptEvent.hintType) { + // Forcible pausing initiated by the audio framework. To prevent data loss, stop the write operation. + case audio.InterruptHint.INTERRUPT_HINT_PAUSE: + isPlay = false; + break; + // Forcible stopping initiated by the audio framework. To prevent data loss, stop the write operation. + case audio.InterruptHint.INTERRUPT_HINT_STOP: + isPlay = false; + break; + // Forcible ducking initiated by the audio framework. + case audio.InterruptHint.INTERRUPT_HINT_DUCK: + break; + // Undocking initiated by the audio framework. + case audio.InterruptHint.INTERRUPT_HINT_UNDUCK: + break; + } + } else if (interruptEvent.forceType == audio.InterruptForceType.INTERRUPT_SHARE) { + switch (interruptEvent.hintType) { + // Notify the application that the rendering starts. + case audio.InterruptHint.INTERRUPT_HINT_RESUME: + startRenderer(); + break; + // Notify the application that the audio stream is interrupted. The application determines whether to continue. (In this example, the application pauses the rendering.) + case audio.InterruptHint.INTERRUPT_HINT_PAUSE: + isPlay = false; + pauseRenderer(); + break; + } + } + }); + + audioRenderer.off('audioInterrupt'); // Unsubscribe from the audio interruption event. This event will no longer be received. + ``` + +10. (Optional) Use **on('markReach')** to subscribe to the mark reached event, and use **off('markReach')** to unsubscribe from the event. + + After the mark reached event is subscribed to, when the number of frames rendered by the audio renderer reaches the specified value, a callback is triggered and the specified value is returned. + + ```js + audioRenderer.on('markReach', (reachNumber) => { + console.info('Mark reach event Received'); + console.info(`The renderer reached frame: ${reachNumber}`); + }); + + audioRenderer.off('markReach'); // Unsubscribe from the mark reached event. This event will no longer be listened for. + ``` + +11. (Optional) Use **on('periodReach')** to subscribe to the period reached event, and use **off('periodReach')** to unsubscribe from the event. + + After the period reached event is subscribed to, each time the number of frames rendered by the audio renderer reaches the specified value, a callback is triggered and the specified value is returned. + + ```js + audioRenderer.on('periodReach', (reachNumber) => { + console.info('Period reach event Received'); + console.info(`In this period, the renderer reached frame: ${reachNumber} `); + }); + + audioRenderer.off('periodReach'); // Unsubscribe from the period reached event. This event will no longer be listened for. + ``` + +12. (Optional) Use **on('stateChange')** to subscribe to audio renderer state changes. + + After the **stateChange** event is subscribed to, when the audio renderer state changes, a callback is triggered and the audio renderer state is returned. + + ```js + audioRenderer.on('stateChange', (audioState) => { + console.info('State change event Received'); + console.info(`Current renderer state is: ${audioState}`); + }); + ``` + +13. (Optional) Handle exceptions of **on()**. + + If the string or the parameter type passed in **on()** is incorrect , the application throws an exception. In this case, you can use **try catch** to capture the exception. + + ```js + try { + audioRenderer.on('invalidInput', () => { // The string does not match. + }) + } catch (err) { + console.info(`Call on function error, ${err}`); // The application throws exception 401. + } + try { + audioRenderer.on(1, () => { // The type of the input parameter is incorrect. + }) + } catch (err) { + console.info(`Call on function error, ${err}`); // The application throws exception 6800101. + } + ``` + +14. (Optional) Refer to the complete example of **on('audioInterrupt')**. + + Create **AudioRender1** and **AudioRender2** in an application, configure the independent interruption mode, and call **on('audioInterrupt')** to subscribe to audio interruption events. At the beginning, **AudioRender1** has the focus. When **AudioRender2** attempts to obtain the focus, **AudioRenderer1** receives a focus transfer notification and the related log information is printed. If the shared mode is used, the log information will not be printed during application running. + + ```js + async runningAudioRender1(){ + let audioStreamInfo = { + samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, + channels: audio.AudioChannel.CHANNEL_1, + sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S32LE, + encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW + } + let audioRendererInfo = { + content: audio.ContentType.CONTENT_TYPE_MUSIC, + usage: audio.StreamUsage.STREAM_USAGE_MEDIA, + rendererFlags: 0 // 0 is the extended flag bit of the audio renderer. The default value is 0. + } + let audioRendererOptions = { + streamInfo: audioStreamInfo, + rendererInfo: audioRendererInfo + } + + // 1.1 Create an instance. + audioRenderer1 = await audio.createAudioRenderer(audioRendererOptions); + console.info("Create audio renderer 1 success."); + + // 1.2 Set the independent mode. + audioRenderer1.setInterruptMode(1).then( data => { + console.info('audioRenderer1 setInterruptMode Success!'); + }).catch((err) => { + console.error(`audioRenderer1 setInterruptMode Fail: ${err}`); + }); + + // 1.3 Set the listener. + audioRenderer1.on('audioInterrupt', async(interruptEvent) => { + console.info(`audioRenderer1 on audioInterrupt : ${JSON.stringify(interruptEvent)}`) + }); + + // 1.4 Start rendering. + await audioRenderer1.start(); + console.info('startAudioRender1 success'); + + // 1.5 Obtain the buffer size, which is the proper minimum buffer size of the audio renderer. You can also select a buffer of another size. + const bufferSize = await audioRenderer1.getBufferSize(); + console.info(`audio bufferSize: ${bufferSize}`); + + // 1.6 Obtain the original audio data file. + let dir = globalThis.fileDir; // You must use the sandbox path. + const path1 = dir + '/music001_48000_32_1.wav'; // The file to render is in the following path: /data/storage/el2/base/haps/entry/files/music001_48000_32_1.wav + console.info(`audioRender1 file path: ${ path1}`); + let ss1 = await fileio.createStream(path1,'r'); + const totalSize1 = fileio.statSync(path1).size; // Size of the file to render. + console.info(`totalSize1 -------: ${totalSize1}`); + let discardHeader = new ArrayBuffer(bufferSize); + ss1.readSync(discardHeader); + let rlen = 0; + rlen += bufferSize; + + // 1.7 Render the original audio data in the buffer by using audioRenderer. + let id = setInterval(async () => { + if (audioRenderer1.state == audio.AudioState.STATE_RELEASED) { // The rendering stops if the audio renderer is in the STATE_RELEASED state. + ss1.closeSync(); + audioRenderer1.stop(); + clearInterval(id); + } + if (audioRenderer1.state == audio.AudioState.STATE_RUNNING) { + if (rlen >= totalSize1) { // The rendering stops if the file finishes reading. + ss1.closeSync(); + await audioRenderer1.stop(); + clearInterval(id); + } + let buf = new ArrayBuffer(bufferSize); + rlen += ss1.readSync(buf); + console.info(`Total bytes read from file: ${rlen}`); + await writeBuffer(buf, that.audioRenderer1); + } else { + console.info('check after next interval'); + } + }, 30); // The timer interval is set based on the audio format. The unit is millisecond. + } + + async runningAudioRender2(){ + let audioStreamInfo = { + samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, + channels: audio.AudioChannel.CHANNEL_1, + sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S32LE, + encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW + } + let audioRendererInfo = { + content: audio.ContentType.CONTENT_TYPE_MUSIC, + usage: audio.StreamUsage.STREAM_USAGE_MEDIA, + rendererFlags: 0 // 0 is the extended flag bit of the audio renderer. The default value is 0. + } + let audioRendererOptions = { + streamInfo: audioStreamInfo, + rendererInfo: audioRendererInfo + } + + // 2.1 Create another instance. + audioRenderer2 = await audio.createAudioRenderer(audioRendererOptions); + console.info("Create audio renderer 2 success."); + + // 2.2 Set the independent mode. + audioRenderer2.setInterruptMode(1).then( data => { + console.info('audioRenderer2 setInterruptMode Success!'); + }).catch((err) => { + console.error(`audioRenderer2 setInterruptMode Fail: ${err}`); + }); + + // 2.3 Set the listener. + audioRenderer2.on('audioInterrupt', async(interruptEvent) => { + console.info(`audioRenderer2 on audioInterrupt : ${JSON.stringify(interruptEvent)}`) + }); + + // 2.4 Start rendering. + await audioRenderer2.start(); + console.info('startAudioRender2 success'); + + // 2.5 Obtain the buffer size. + const bufferSize = await audioRenderer2.getBufferSize(); + console.info(`audio bufferSize: ${bufferSize}`); + + // 2.6 Read the original audio data file. + let dir = globalThis.fileDir; // You must use the sandbox path. + const path2 = dir + '/music002_48000_32_1.wav'; // The file to render is in the following path: /data/storage/el2/base/haps/entry/files/music002_48000_32_1.wav + console.error(`audioRender1 file path: ${ path2}`); + let ss2 = await fileio.createStream(path2,'r'); + const totalSize2 = fileio.statSync(path2).size; // Size of the file to render. + console.error(`totalSize2 -------: ${totalSize2}`); + let discardHeader2 = new ArrayBuffer(bufferSize); + ss2.readSync(discardHeader2); + let rlen = 0; + rlen += bufferSize; + + // 2.7 Render the original audio data in the buffer by using audioRenderer. + let id = setInterval(async () => { + if (audioRenderer2.state == audio.AudioState.STATE_RELEASED) { // The rendering stops if the audio renderer is in the STATE_RELEASED state. + ss2.closeSync(); + that.audioRenderer2.stop(); + clearInterval(id); + } + if (audioRenderer1.state == audio.AudioState.STATE_RUNNING) { + if (rlen >= totalSize2) { // The rendering stops if the file finishes reading. + ss2.closeSync(); + await audioRenderer2.stop(); + clearInterval(id); + } + let buf = new ArrayBuffer(bufferSize); + rlen += ss2.readSync(buf); + console.info(`Total bytes read from file: ${rlen}`); + await writeBuffer(buf, that.audioRenderer2); + } else { + console.info('check after next interval'); + } + }, 30); // The timer interval is set based on the audio format. The unit is millisecond. + } + + async writeBuffer(buf, audioRender) { + let writtenbytes; + await audioRender.write(buf).then((value) => { + writtenbytes = value; + console.info(`Actual written bytes: ${writtenbytes} `); + }); + if (typeof(writtenbytes) != 'number' || writtenbytes < 0) { + console.error('get Write buffer failed. check the state of renderer'); + } + } + + // Integrated invoking entry. + async test(){ + await runningAudioRender1(); + await runningAudioRender2(); + } + + ``` diff --git a/en/application-dev/media/audio-routing-manager.md b/en/application-dev/media/audio-routing-manager.md new file mode 100644 index 0000000000000000000000000000000000000000..55febdca0fad968d946601fce4faed99bc148dd2 --- /dev/null +++ b/en/application-dev/media/audio-routing-manager.md @@ -0,0 +1,111 @@ +# Audio Routing and Device Management Development + +## Overview + +The **AudioRoutingManager** module provides APIs for audio routing and device management. You can use the APIs to obtain the current input and output audio devices, listen for connection status changes of audio devices, and activate communication devices. + +## Working Principles + +The figure below shows the common APIs provided by the **AudioRoutingManager** module. + +**Figure 1** Common APIs of AudioRoutingManager + +![en-us_image_audio_routing_manager](figures/en-us_image_audio_routing_manager.png) + +You can use these APIs to obtain the device list, subscribe to or unsubscribe from device connection status changes, activate communication devices, and obtain their activation status. For details, see [Audio Management](../reference/apis/js-apis-audio.md). + + +## How to Develop + +For details about the APIs, see [AudioRoutingManager in Audio Management](../reference/apis/js-apis-audio.md#audioroutingmanager9). + +1. Obtain an **AudioRoutingManager** instance. + + Before using an API in **AudioRoutingManager**, you must use **getRoutingManager()** to obtain an **AudioRoutingManager** instance. + + ```js + import audio from '@ohos.multimedia.audio'; + async loadAudioRoutingManager() { + var audioRoutingManager = await audio.getAudioManager().getRoutingManager(); + console.info('audioRoutingManager------create-------success.'); + } + + ``` + +2. (Optional) Obtain the device list and subscribe to device connection status changes. + + To obtain the device list (such as input, output, distributed input, and distributed output devices) or listen for connection status changes of audio devices, refer to the following code: + + ```js + import audio from '@ohos.multimedia.audio'; + // Obtain an AudioRoutingManager instance. + async loadAudioRoutingManager() { + var audioRoutingManager = await audio.getAudioManager().getRoutingManager(); + console.info('audioRoutingManager------create-------success.'); + } + // Obtain information about all audio devices. (You can set DeviceFlag as required.) + async getDevices() { + await loadAudioRoutingManager(); + await audioRoutingManager.getDevices(audio.DeviceFlag.ALL_DEVICES_FLAG).then((data) => { + console.info(`getDevices success and data is: ${JSON.stringify(data)}.`); + }); + } + // Subscribe to connection status changes of audio devices. + async onDeviceChange() { + await loadAudioRoutingManager(); + await audioRoutingManager.on('deviceChange', audio.DeviceFlag.ALL_DEVICES_FLAG, (deviceChanged) => { + console.info('on device change type : ' + deviceChanged.type); + console.info('on device descriptor size : ' + deviceChanged.deviceDescriptors.length); + console.info('on device change descriptor : ' + deviceChanged.deviceDescriptors[0].deviceRole); + console.info('on device change descriptor : ' + deviceChanged.deviceDescriptors[0].deviceType); + }); + } + // Unsubscribe from the connection status changes of audio devices. + async offDeviceChange() { + await loadAudioRoutingManager(); + await audioRoutingManager.off('deviceChange', (deviceChanged) => { + console.info('off device change type : ' + deviceChanged.type); + console.info('off device descriptor size : ' + deviceChanged.deviceDescriptors.length); + console.info('off device change descriptor : ' + deviceChanged.deviceDescriptors[0].deviceRole); + console.info('off device change descriptor : ' + deviceChanged.deviceDescriptors[0].deviceType); + }); + } + // Complete process: Call APIs to obtain all devices and subscribe to device changes, then manually change the connection status of a device (for example, wired headset), and finally call APIs to obtain all devices and unsubscribe from the device changes. + async test(){ + await getDevices(); + await onDeviceChange()(); + // Manually disconnect or connect devices. + await getDevices(); + await offDeviceChange(); + } + ``` + +3. (Optional) Activate a communication device and obtain its activation status. + + ```js + import audio from '@ohos.multimedia.audio'; + // Obtain an AudioRoutingManager instance. + async loadAudioRoutingManager() { + var audioRoutingManager = await audio.getAudioManager().getRoutingManager(); + console.info('audioRoutingManager------create-------success.'); + } + // Activate a communication device. + async setCommunicationDevice() { + await loadAudioRoutingManager(); + await audioRoutingManager.setCommunicationDevice(audio.CommunicationDeviceType.SPEAKER, true).then(() => { + console.info('setCommunicationDevice true is success.'); + }); + } + // Obtain the activation status of the communication device. + async isCommunicationDeviceActive() { + await loadAudioRoutingManager(); + await audioRoutingManager.isCommunicationDeviceActive(audio.CommunicationDeviceType.SPEAKER).then((value) => { + console.info(`CommunicationDevice state is: ${value}.`); + }); + } + // Complete process: Activate a device and obtain the activation status. + async test(){ + await setCommunicationDevice(); + await isCommunicationDeviceActive(); + } + ``` diff --git a/en/application-dev/media/audio-stream-manager.md b/en/application-dev/media/audio-stream-manager.md index eb89957e9b8793b149c368445f1232bf0ff3b563..44ec37cd11f3666131214e5e908a1ce761fea111 100644 --- a/en/application-dev/media/audio-stream-manager.md +++ b/en/application-dev/media/audio-stream-manager.md @@ -1,57 +1,61 @@ # Audio Stream Management Development -## When to Use +## Introduction You can use **AudioStreamManager** to manage audio streams. -### Development Process +## Working Principles -During application development, use **getStreamManager()** to create an **AudioStreamManager** instance. Then, you can call **on('audioRendererChange')** or **on('audioCapturerChange')** to listen for status, client, and audio attribute changes of the audio playback or recording application. To cancel the listening for these changes, call **off('audioRendererChange')** or **off('audioCapturerChange')**. You can call **getCurrentAudioRendererInfoArray()** to obtain information about the audio playback application, such as the unique audio stream ID, UID of the audio playback client, and audio status. Similarly, you can call **getCurrentAudioCapturerInfoArray()** to obtain information about the audio recording application. The figure below shows the invoking relationship. +The following figure shows the calling relationship of **AudioStreamManager** APIs. -For details about the APIs, see [AudioStreamManager](../reference/apis/js-apis-audio.md#audiostreammanager9). +**Figure 1** AudioStreamManager API calling relationship -**Figure 1** Audio stream management invoking relationship +![en-us_image_audio_stream_manager](figures/en-us_image_audio_stream_manager.png) -![](figures/en-us_image_audio_stream_manager.png) +**NOTE**: During application development, use **getStreamManager()** to create an **AudioStreamManager** instance. Then, you can call **on('audioRendererChange')** or **on('audioCapturerChange')** to listen for status, client, and audio attribute changes of the audio playback or recording application. To cancel the listening for these changes, call **off('audioRendererChange')** or **off('audioCapturerChange')**. You can call **getCurrentAudioRendererInfoArray()** to obtain information about the audio playback application, such as the unique audio stream ID, UID of the audio playback client, and audio status. Similarly, you can call **getCurrentAudioCapturerInfoArray()** to obtain information about the audio recording application. ## How to Develop +For details about the APIs, see [AudioStreamManager](../reference/apis/js-apis-audio.md#audiostreammanager9). + 1. Create an **AudioStreamManager** instance. Before using **AudioStreamManager** APIs, you must use **getStreamManager()** to create an **AudioStreamManager** instance. ```js - var audioStreamManager = audio.getStreamManager(); + var audioManager = audio.getAudioManager(); + var audioStreamManager = audioManager.getStreamManager(); ``` 2. (Optional) Call **on('audioRendererChange')** to listen for audio renderer changes. -If an application needs to receive notifications when the audio playback application status, audio playback client, or audio attribute changes, it can subscribe to this event. For more events that can be subscribed to, see [Audio Management](../reference/apis/js-apis-audio.md). - ```js - audioStreamManager.on('audioRendererChange', (AudioRendererChangeInfoArray) => { - for (let i = 0; i < AudioRendererChangeInfoArray.length; i++) { - AudioRendererChangeInfo = AudioRendererChangeInfoArray[i]; - console.info('## RendererChange on is called for ' + i + ' ##'); - console.info('StreamId for ' + i + ' is:' + AudioRendererChangeInfo.streamId); - console.info('ClientUid for ' + i + ' is:' + AudioRendererChangeInfo.clientUid); - console.info('Content for ' + i + ' is:' + AudioRendererChangeInfo.rendererInfo.content); - console.info('Stream for ' + i + ' is:' + AudioRendererChangeInfo.rendererInfo.usage); - console.info('Flag ' + i + ' is:' + AudioRendererChangeInfo.rendererInfo.rendererFlags); - console.info('State for ' + i + ' is:' + AudioRendererChangeInfo.rendererState); - var devDescriptor = AudioRendererChangeInfo.deviceDescriptors; - for (let j = 0; j < AudioRendererChangeInfo.deviceDescriptors.length; j++) { - console.info('Id:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].id); - console.info('Type:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].deviceType); - console.info('Role:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].deviceRole); - console.info('Name:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].name); - console.info('Address:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].address); - console.info('SampleRates:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].sampleRates[0]); - console.info('ChannelCounts' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].channelCounts[0]); - console.info('ChannelMask:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].channelMasks); - } - } - }); - ``` + If an application needs to receive notifications when the audio playback application status, audio playback client, or audio attribute changes, it can subscribe to this event. For more events that can be subscribed to, see [Audio Management](../reference/apis/js-apis-audio.md). + + ```js + audioStreamManager.on('audioRendererChange', (AudioRendererChangeInfoArray) => { + for (let i = 0; i < AudioRendererChangeInfoArray.length; i++) { + AudioRendererChangeInfo = AudioRendererChangeInfoArray[i]; + console.info('## RendererChange on is called for ' + i + ' ##'); + console.info('StreamId for ' + i + ' is:' + AudioRendererChangeInfo.streamId); + console.info('ClientUid for ' + i + ' is:' + AudioRendererChangeInfo.clientUid); + console.info('Content for ' + i + ' is:' + AudioRendererChangeInfo.rendererInfo.content); + console.info('Stream for ' + i + ' is:' + AudioRendererChangeInfo.rendererInfo.usage); + console.info('Flag ' + i + ' is:' + AudioRendererChangeInfo.rendererInfo.rendererFlags); + console.info('State for ' + i + ' is:' + AudioRendererChangeInfo.rendererState); + var devDescriptor = AudioRendererChangeInfo.deviceDescriptors; + for (let j = 0; j < AudioRendererChangeInfo.deviceDescriptors.length; j++) { + console.info('Id:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].id); + console.info('Type:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].deviceType); + console.info('Role:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].deviceRole); + console.info('Name:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].name); + console.info('Address:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].address); + console.info('SampleRates:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].sampleRates[0]); + console.info('ChannelCounts' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].channelCounts[0]); + console.info('ChannelMask:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].channelMasks); + } + } + }); + ``` 3. (Optional) Call **off('audioRendererChange')** to cancel listening for audio renderer changes. @@ -61,30 +65,31 @@ If an application needs to receive notifications when the audio playback applica ``` 4. (Optional) Call **on('audioCapturerChange')** to listen for audio capturer changes. -If an application needs to receive notifications when the audio recording application status, audio recording client, or audio attribute changes, it can subscribe to this event. For more events that can be subscribed to, see [Audio Management](../reference/apis/js-apis-audio.md). - ```js - audioStreamManager.on('audioCapturerChange', (AudioCapturerChangeInfoArray) => { - for (let i = 0; i < AudioCapturerChangeInfoArray.length; i++) { - console.info(' ## audioCapturerChange on is called for element ' + i + ' ##'); - console.info('StreamId for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].streamId); - console.info('ClientUid for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].clientUid); - console.info('Source for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].capturerInfo.source); - console.info('Flag ' + i + 'is:' + AudioCapturerChangeInfoArray[i].capturerInfo.capturerFlags); - console.info('State for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].capturerState); - for (let j = 0; j < AudioCapturerChangeInfoArray[i].deviceDescriptors.length; j++) { - console.info('Id:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].id); - console.info('Type:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].deviceType); - console.info('Role:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].deviceRole); - console.info('Name:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].name); - console.info('Address:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].address); - console.info('SampleRates:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].sampleRates[0]); - console.info('ChannelCounts' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].channelCounts[0]); - console.info('ChannelMask:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].channelMasks); - } - } - }); - ``` + If an application needs to receive notifications when the audio recording application status, audio recording client, or audio attribute changes, it can subscribe to this event. For more events that can be subscribed to, see [Audio Management](../reference/apis/js-apis-audio.md). + + ```js + audioStreamManager.on('audioCapturerChange', (AudioCapturerChangeInfoArray) => { + for (let i = 0; i < AudioCapturerChangeInfoArray.length; i++) { + console.info(' ## audioCapturerChange on is called for element ' + i + ' ##'); + console.info('StreamId for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].streamId); + console.info('ClientUid for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].clientUid); + console.info('Source for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].capturerInfo.source); + console.info('Flag ' + i + 'is:' + AudioCapturerChangeInfoArray[i].capturerInfo.capturerFlags); + console.info('State for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].capturerState); + for (let j = 0; j < AudioCapturerChangeInfoArray[i].deviceDescriptors.length; j++) { + console.info('Id:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].id); + console.info('Type:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].deviceType); + console.info('Role:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].deviceRole); + console.info('Name:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].name); + console.info('Address:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].address); + console.info('SampleRates:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].sampleRates[0]); + console.info('ChannelCounts' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].channelCounts[0]); + console.info('ChannelMask:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].channelMasks); + } + } + }); + ``` 5. (Optional) Call **off('audioCapturerChange')** to cancel listening for audio capturer changes. @@ -94,65 +99,66 @@ If an application needs to receive notifications when the audio recording applic ``` 6. (Optional) Call **getCurrentAudioRendererInfoArray()** to obtain information about the current audio renderer. -This API can be used to obtain the unique ID of the audio stream, UID of the audio playback client, audio status, and other information about the audio player. Before calling this API, a third-party application must have the **ohos.permission.USE_BLUETOOTH** permission configured, for the device name and device address to be displayed correctly. - - ```js - await audioStreamManager.getCurrentAudioRendererInfoArray().then( function (AudioRendererChangeInfoArray) { - console.info('######### Get Promise is called ##########'); - if (AudioRendererChangeInfoArray != null) { - for (let i = 0; i < AudioRendererChangeInfoArray.length; i++) { - AudioRendererChangeInfo = AudioRendererChangeInfoArray[i]; - console.info('StreamId for ' + i +' is:' + AudioRendererChangeInfo.streamId); - console.info('ClientUid for ' + i + ' is:' + AudioRendererChangeInfo.clientUid); - console.info('Content ' + i + ' is:' + AudioRendererChangeInfo.rendererInfo.content); - console.info('Stream' + i +' is:' + AudioRendererChangeInfo.rendererInfo.usage); - console.info('Flag' + i + ' is:' + AudioRendererChangeInfo.rendererInfo.rendererFlags); - console.info('State for ' + i + ' is:' + AudioRendererChangeInfo.rendererState); - var devDescriptor = AudioRendererChangeInfo.deviceDescriptors; - for (let j = 0; j < AudioRendererChangeInfo.deviceDescriptors.length; j++) { - console.info('Id:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].id); - console.info('Type:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].deviceType); - console.info('Role:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].deviceRole); - console.info('Name:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].name); - console.info('Address:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].address); - console.info('SampleRates:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].sampleRates[0]); - console.info('ChannelCounts' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].channelCounts[0]); - console.info('ChannelMask:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].channelMasks); - } - } - } - }).catch((err) => { - console.log('getCurrentAudioRendererInfoArray :ERROR: ' + err.message); - }); - ``` + + This API can be used to obtain the unique ID of the audio stream, UID of the audio playback client, audio status, and other information about the audio player. Before calling this API, a third-party application must have the **ohos.permission.USE_BLUETOOTH** permission configured, for the device name and device address to be displayed correctly. + + ```js + await audioStreamManager.getCurrentAudioRendererInfoArray().then( function (AudioRendererChangeInfoArray) { + console.info('######### Get Promise is called ##########'); + if (AudioRendererChangeInfoArray != null) { + for (let i = 0; i < AudioRendererChangeInfoArray.length; i++) { + AudioRendererChangeInfo = AudioRendererChangeInfoArray[i]; + console.info('StreamId for ' + i +' is:' + AudioRendererChangeInfo.streamId); + console.info('ClientUid for ' + i + ' is:' + AudioRendererChangeInfo.clientUid); + console.info('Content ' + i + ' is:' + AudioRendererChangeInfo.rendererInfo.content); + console.info('Stream' + i +' is:' + AudioRendererChangeInfo.rendererInfo.usage); + console.info('Flag' + i + ' is:' + AudioRendererChangeInfo.rendererInfo.rendererFlags); + console.info('State for ' + i + ' is:' + AudioRendererChangeInfo.rendererState); + var devDescriptor = AudioRendererChangeInfo.deviceDescriptors; + for (let j = 0; j < AudioRendererChangeInfo.deviceDescriptors.length; j++) { + console.info('Id:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].id); + console.info('Type:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].deviceType); + console.info('Role:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].deviceRole); + console.info('Name:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].name); + console.info('Address:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].address); + console.info('SampleRates:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].sampleRates[0]); + console.info('ChannelCounts' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].channelCounts[0]); + console.info('ChannelMask:' + i + ':' + AudioRendererChangeInfo.deviceDescriptors[j].channelMasks); + } + } + } + }).catch((err) => { + console.log('getCurrentAudioRendererInfoArray :ERROR: ' + err.message); + }); + ``` 7. (Optional) Call **getCurrentAudioCapturerInfoArray()** to obtain information about the current audio capturer. -This API can be used to obtain the unique ID of the audio stream, UID of the audio recording client, audio status, and other information about the audio capturer. Before calling this API, a third-party application must have the **ohos.permission.USE_BLUETOOTH** permission configured, for the device name and device address to be displayed correctly. - - ```js - await audioStreamManager.getCurrentAudioCapturerInfoArray().then( function (AudioCapturerChangeInfoArray) { - console.info('getCurrentAudioCapturerInfoArray: **** Get Promise Called ****'); - if (AudioCapturerChangeInfoArray != null) { - for (let i = 0; i < AudioCapturerChangeInfoArray.length; i++) { - console.info('StreamId for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].streamId); - console.info('ClientUid for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].clientUid); - console.info('Source for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].capturerInfo.source); - console.info('Flag ' + i + 'is:' + AudioCapturerChangeInfoArray[i].capturerInfo.capturerFlags); - console.info('State for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].capturerState); - var devDescriptor = AudioCapturerChangeInfoArray[i].deviceDescriptors; - for (let j = 0; j < AudioCapturerChangeInfoArray[i].deviceDescriptors.length; j++) { - console.info('Id:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].id); - console.info('Type:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].deviceType); - console.info('Role:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].deviceRole); - console.info('Name:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].name) - console.info('Address:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].address); - console.info('SampleRates:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].sampleRates[0]); - console.info('ChannelCounts' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].channelCounts[0]); - console.info('ChannelMask:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].channelMasks); - } - } - } - }).catch((err) => { - console.log('getCurrentAudioCapturerInfoArray :ERROR: ' + err.message); - }); - ``` + This API can be used to obtain the unique ID of the audio stream, UID of the audio recording client, audio status, and other information about the audio capturer. Before calling this API, a third-party application must have the **ohos.permission.USE_BLUETOOTH** permission configured, for the device name and device address to be displayed correctly. + + ```js + await audioStreamManager.getCurrentAudioCapturerInfoArray().then( function (AudioCapturerChangeInfoArray) { + console.info('getCurrentAudioCapturerInfoArray: **** Get Promise Called ****'); + if (AudioCapturerChangeInfoArray != null) { + for (let i = 0; i < AudioCapturerChangeInfoArray.length; i++) { + console.info('StreamId for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].streamId); + console.info('ClientUid for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].clientUid); + console.info('Source for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].capturerInfo.source); + console.info('Flag ' + i + 'is:' + AudioCapturerChangeInfoArray[i].capturerInfo.capturerFlags); + console.info('State for ' + i + 'is:' + AudioCapturerChangeInfoArray[i].capturerState); + var devDescriptor = AudioCapturerChangeInfoArray[i].deviceDescriptors; + for (let j = 0; j < AudioCapturerChangeInfoArray[i].deviceDescriptors.length; j++) { + console.info('Id:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].id); + console.info('Type:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].deviceType); + console.info('Role:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].deviceRole); + console.info('Name:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].name) + console.info('Address:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].address); + console.info('SampleRates:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].sampleRates[0]); + console.info('ChannelCounts' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].channelCounts[0]); + console.info('ChannelMask:' + i + ':' + AudioCapturerChangeInfoArray[i].deviceDescriptors[j].channelMasks); + } + } + } + }).catch((err) => { + console.log('getCurrentAudioCapturerInfoArray :ERROR: ' + err.message); + }); + ``` diff --git a/en/application-dev/media/audio-volume-manager.md b/en/application-dev/media/audio-volume-manager.md new file mode 100644 index 0000000000000000000000000000000000000000..2063e831f886ae3e6e1fe0a5bd428da194d00227 --- /dev/null +++ b/en/application-dev/media/audio-volume-manager.md @@ -0,0 +1,126 @@ +# Volume Management Development + +## Overview + +The **AudioVolumeManager** module provides APIs for volume management. You can use the APIs to obtain the volume of a stream, listen for ringer mode changes, and mute a microphone. + +## Working Principles + +The figure below shows the common APIs provided by the **AudioVolumeManager** module. + +**Figure 1** Common APIs of AudioVolumeManager + +![en-us_image_audio_volume_manager](figures/en-us_image_audio_volume_manager.png) + +**AudioVolumeManager** provides the APIs for subscribing to system volume changes and obtaining the audio volume group manager (an **AudioVolumeGroupManager** instance). Before calling any API in **AudioVolumeGroupManager**, you must call **getVolumeGroupManager** to obtain an **AudioVolumeGroupManager** instance. You can use the APIs provided by **AudioVolumeGroupManager** to obtain the volume of a stream, mute a microphone, and listen for microphone state changes. For details, see [Audio Management](../reference/apis/js-apis-audio.md). + +## Constraints + +Before developing a microphone management application, configure the permission **ohos.permission.MICROPHONE** for the application. To set the microphone state, configure the permission **ohos.permission.MANAGE_AUDIO_CONFIG** (a system permission). For details about the permission configuration, see [Permission Application Guide](../security/accesstoken-guidelines.md). + +## How to Develop + +For details about the APIs, see [AudioVolumeManager in Audio Management](../reference/apis/js-apis-audio.md#audiovolumemanager9) + +1. Obtain an **AudioVolumeGroupManager** instance. + + Before using an API in **AudioVolumeGroupManager**, you must use **getVolumeGroupManager()** to obtain an **AudioStreamManager** instance. + + ```js + import audio from '@ohos.multimedia.audio'; + async loadVolumeGroupManager() { + const groupid = audio.DEFAULT_VOLUME_GROUP_ID; + var audioVolumeGroupManager = await audio.getAudioManager().getVolumeManager().getVolumeGroupManager(groupid); + console.error('audioVolumeGroupManager create success.'); + } + + ``` + +2. (Optional) Obtain the volume information and ringer mode. + + To obtain the volume information (such as the ringtone, voice call, media, and voice assistant) of an audio stream or obtain the ringer mode (silent, vibration, or normal) of the current device, refer to the code below. For more details, see [Audio Management](../reference/apis/js-apis-audio.md). + + ```js + import audio from '@ohos.multimedia.audio'; + async loadVolumeGroupManager() { + const groupid = audio.DEFAULT_VOLUME_GROUP_ID; + var audioVolumeGroupManager = await audio.getAudioManager().getVolumeManager().getVolumeGroupManager(groupid); + console.info('audioVolumeGroupManager create success.'); + } + + // Obtain the volume of a stream. The value ranges from 0 to 15. + async getVolume() { + await loadVolumeGroupManager(); + await audioVolumeGroupManager.getVolume(audio.AudioVolumeType.MEDIA).then((value) => { + console.info(`getVolume success and volume is: ${value}.`); + }); + } + // Obtain the minimum volume of a stream. + async getMinVolume() { + await loadVolumeGroupManager(); + await audioVolumeGroupManager.getMinVolume(audio.AudioVolumeType.MEDIA).then((value) => { + console.info(`getMinVolume success and volume is: ${value}.`); + }); + } + // Obtain the maximum volume of a stream. + async getMaxVolume() { + await loadVolumeGroupManager(); + await audioVolumeGroupManager.getMaxVolume(audio.AudioVolumeType.MEDIA).then((value) => { + console.info(`getMaxVolume success and volume is: ${value}.`); + }); + } + // Obtain the ringer mode in use: silent (0) | vibrate (1) | normal (2). + async getRingerMode() { + await loadVolumeGroupManager(); + await audioVolumeGroupManager.getRingerMode().then((value) => { + console.info(`getRingerMode success and RingerMode is: ${value}.`); + }); + } + ``` + +3. (Optional) Obtain and set the microphone state, and subscribe to microphone state changes. + + To obtain and set the microphone state or subscribe to microphone state changes, refer to the following code: + + ```js + import audio from '@ohos.multimedia.audio'; + async loadVolumeGroupManager() { + const groupid = audio.DEFAULT_VOLUME_GROUP_ID; + var audioVolumeGroupManager = await audio.getAudioManager().getVolumeManager().getVolumeGroupManager(groupid); + console.info('audioVolumeGroupManager create success.'); + } + + async on() { // Subscribe to microphone state changes. + await loadVolumeGroupManager(); + await audioVolumeGroupManager.audioVolumeGroupManager.on('micStateChange', (micStateChange) => { + console.info(`Current microphone status is: ${micStateChange.mute} `); + }); + } + + async isMicrophoneMute() { // Check whether the microphone is muted. + await audioVolumeGroupManager.audioVolumeGroupManager.isMicrophoneMute().then((value) => { + console.info(`isMicrophoneMute is: ${value}.`); + }); + } + + async setMicrophoneMuteTrue() { // Mute the microphone. + await loadVolumeGroupManager(); + await audioVolumeGroupManager.audioVolumeGroupManager.setMicrophoneMute(true).then(() => { + console.info('setMicrophoneMute to mute.'); + }); + } + + async setMicrophoneMuteFalse() { // Unmute the microphone. + await loadVolumeGroupManager(); + await audioVolumeGroupManager.audioVolumeGroupManager.setMicrophoneMute(false).then(() => { + console.info('setMicrophoneMute to not mute.'); + }); + } + async test(){ // Complete process: Subscribe to microphone state changes, obtain the microphone state, mute the microphone, obtain the microphone state, and unmute the microphone. + await on(); + await isMicrophoneMute(); + await setMicrophoneMuteTrue(); + await isMicrophoneMute(); + await setMicrophoneMuteFalse(); + } + ``` diff --git a/en/application-dev/media/avsession-guidelines.md b/en/application-dev/media/avsession-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..6106509fbfe30a7b437ec574843f50cd7bf1aceb --- /dev/null +++ b/en/application-dev/media/avsession-guidelines.md @@ -0,0 +1,629 @@ +# AVSession Development + +## Development for the Session Access End + +### Basic Concepts +- **AVMetadata**: media data related attributes, including the IDs of the current media asset, previous media asset, and next media asset, title, author, album, writer, and duration. +- **AVSessionDescriptor**: descriptor about a media session, including the session ID, session type (audio/video), custom session name (**sessionTag**), and information about the corresponding application (**elementName**). +- **AVPlaybackState**: information related to the media playback state, including the playback state, position, speed, buffered time, loop mode, and whether the media asset is favorited (**isFavorite**). + +### Available APIs +The table below lists the APIs available for the development of the session access end. The APIs use either a callback or promise to return the result. The APIs listed below use a callback, which provide the same functions as their counterparts that use a promise. For details, see [AVSession Management](../reference/apis/js-apis-avsession.md). + +Table 1 Common APIs for session access end development + +| API | Description | +|----------------------------------------------------------------------------------|-------------| +| createAVSession(context: Context, tag: string, type: AVSessionType, callback: AsyncCallback\): void | Creates a session.| +| setAVMetadata(data: AVMetadata, callback: AsyncCallback\): void | Sets session metadata. | +| setAVPlaybackState(state: AVPlaybackState, callback: AsyncCallback\): void | Sets the playback state information. | +| setLaunchAbility(ability: WantAgent, callback: AsyncCallback\): void | Sets the launcher ability.| +| getController(callback: AsyncCallback\): void | Obtains the controller of this session.| +| getOutputDevice(callback: AsyncCallback\): void | Obtains the output device information. | +| activate(callback: AsyncCallback\): void | Activates this session. | +| destroy(callback: AsyncCallback\): void | Destroys this session. | + +### How to Develop +1. Import the modules. + +```js +import avSession from '@ohos.multimedia.avsession'; +import wantAgent from '@ohos.wantAgent'; +import featureAbility from '@ohos.ability.featureAbility'; +``` + +2. Create and activate a session. +```js +// Define global variables. +let mediaFavorite = false; +let currentSession = null; +let context = featureAbility.getContext(); + +// Create an audio session. +avSession.createAVSession(context, "AudioAppSample", 'audio').then((session) => { + currentSession = session; + currentSession.activate(); // Activate the session. +}).catch((err) => { + console.info(`createAVSession : ERROR : ${err.message}`); +}); +``` + +3. Set the session information, including: +- Session metadata. In addition to the current media asset ID (mandatory), you can set the title, album, author, duration, and previous/next media asset ID. For details about the session metadata, see **AVMetadata** in the API document. +- Launcher ability, which is implemented by calling an API of **WantAgent**. Generally, **WantAgent** is used to encapsulate want information. For more information, see [wantAgent](../reference/apis/js-apis-wantAgent.md). +- Playback state information. +```js +// Set the session metadata. +let metadata = { + assetId: "121278", + title: "lose yourself", + artist: "Eminem", + author: "ST", + album: "Slim shady", + writer: "ST", + composer: "ST", + duration: 2222, + mediaImage: "https://www.example.com/example.jpg", // Set it based on your project requirements. + subtitle: "8 Mile", + description: "Rap", + lyric: "https://www.example.com/example.lrc", // Set it based on your project requirements. + previousAssetId: "121277", + nextAssetId: "121279", +}; +currentSession.setAVMetadata(metadata).then(() => { + console.info('setAVMetadata successfully'); +}).catch((err) => { + console.info(`setAVMetadata : ERROR : ${err.message}`); +}); +``` + +```js +// Set the launcher ability. +let wantAgentInfo = { + wants: [ + { + bundleName: "com.neu.setResultOnAbilityResultTest1", + abilityName: "com.example.test.MainAbility", + } + ], + operationType: wantAgent.OperationType.START_ABILITIES, + requestCode: 0, + wantAgentFlags:[wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] +} + +wantAgent.getWantAgent(wantAgentInfo).then((agent) => { + currentSession.setLaunchAbility(agent).then(() => { + console.info('setLaunchAbility successfully'); + }).catch((err) => { + console.info(`setLaunchAbility : ERROR : ${err.message}`); + }); +}); +``` + +```js +// Set the playback state information. +let PlaybackState = { + state: avSession.PlaybackState.PLAYBACK_STATE_STOP, + speed: 1.0, + position:{elapsedTime: 0, updateTime: (new Date()).getTime()}, + bufferedTime: 1000, + loopMode: avSession.LoopMode.LOOP_MODE_SEQUENCE, + isFavorite: false, +}; +currentSession.setAVPlaybackState(PlaybackState).then(() => { + console.info('setAVPlaybackState successfully'); +}).catch((err) => { + console.info(`setAVPlaybackState : ERROR : ${err.message}`); +}); +``` + +```js +// Obtain the controller of this session. +currentSession.getController().then((selfController) => { + console.info('getController successfully'); +}).catch((err) => { + console.info(`getController : ERROR : ${err.message}`); +}); +``` + +```js +// Obtain the output device information. +currentSession.getOutputDevice().then((outputInfo) => { + console.info(`getOutputDevice successfully, deviceName : ${outputInfo.deviceName}`); +}).catch((err) => { + console.info(`getOutputDevice : ERROR : ${err.message}`); +}); +``` + +4. Subscribe to control command events. +```js +// Subscribe to the 'play' command event. +currentSession.on('play', () => { + console.log ("Call AudioPlayer.play."); + // Set the playback state information. + currentSession.setAVPlaybackState({state: avSession.PlaybackState.PLAYBACK_STATE_PLAY}).then(() => { + console.info('setAVPlaybackState successfully'); + }).catch((err) => { + console.info(`setAVPlaybackState : ERROR : ${err.message}`); + }); +}); + + +// Subscribe to the 'pause' command event. +currentSession.on('pause', () => { + console.log ("Call AudioPlayer.pause."); + // Set the playback state information. + currentSession.setAVPlaybackState({state: avSession.PlaybackState.PLAYBACK_STATE_PAUSE}).then(() => { + console.info('setAVPlaybackState successfully'); + }).catch((err) => { + console.info(`setAVPlaybackState : ERROR : ${err.message}`); + }); +}); + +// Subscribe to the 'stop' command event. +currentSession.on('stop', () => { + console.log ("Call AudioPlayer.stop."); + // Set the playback state information. + currentSession.setAVPlaybackState({state: avSession.PlaybackState.PLAYBACK_STATE_STOP}).then(() => { + console.info('setAVPlaybackState successfully'); + }).catch((err) => { + console.info(`setAVPlaybackState : ERROR : ${err.message}`); + }); +}); + +// Subscribe to the 'playNext' command event. +currentSession.on('playNext', () => { + // When the media file is not ready, download and cache the media file, and set the 'PREPARE' state. + currentSession.setAVPlaybackState({state: avSession.PlaybackState.PLAYBACK_STATE_PREPARE}).then(() => { + console.info('setAVPlaybackState successfully'); + }).catch((err) => { + console.info(`setAVPlaybackState : ERROR : ${err.message}`); + }); + // The media file is obtained. + currentSession.setAVMetadata({assetId: '58970105', title: 'See you tomorrow'}).then(() => { + console.info('setAVMetadata successfully'); + }).catch((err) => { + console.info(`setAVMetadata : ERROR : ${err.message}`); + }); + console.log ("Call AudioPlayer.play."); + // Set the playback state information. + let time = (new Data()).getTime(); + currentSession.setAVPlaybackState({state: avSession.PlaybackState.PLAYBACK_STATE_PLAY, position: {elapsedTime: 0, updateTime: time}, bufferedTime:2000}).then(() => { + console.info('setAVPlaybackState successfully'); + }).catch((err) => { + console.info(`setAVPlaybackState : ERROR : ${err.message}`); + }); +}); + +// Subscribe to the 'fastForward' command event. +currentSession.on('fastForward', () => { + console.log("Call AudioPlayer for fast forwarding."); + // Set the playback state information. + currentSession.setAVPlaybackState({speed: 2.0}).then(() => { + console.info('setAVPlaybackState successfully'); + }).catch((err) => { + console.info(`setAVPlaybackState : ERROR : ${err.message}`); + }); +}); + +// Subscribe to the 'seek' command event. +currentSession.on('seek', (time) => { + console.log("Call AudioPlayer.seek."); + // Set the playback state information. + currentSession.setAVPlaybackState({position: {elapsedTime: time, updateTime: (new Data()).getTime()}}).then(() => { + console.info('setAVPlaybackState successfully'); + }).catch((err) => { + console.info(`setAVPlaybackState : ERROR : ${err.message}`); + }); +}); + +// Subscribe to the 'setSpeed' command event. +currentSession.on('setSpeed', (speed) => { + console.log(`Call AudioPlayer to set the speed to ${speed}`); + // Set the playback state information. + currentSession.setAVPlaybackState({speed: speed}).then(() => { + console.info('setAVPlaybackState successfully'); + }).catch((err) => { + console.info(`setAVPlaybackState : ERROR : ${err.message}`); + }); +}); + +// Subscribe to the 'setLoopMode' command event. +currentSession.on('setLoopMode', (mode) => { + console.log(`The application switches to the loop mode ${mode}`); + // Set the playback state information. + currentSession.setAVPlaybackState({loopMode: mode}).then(() => { + console.info('setAVPlaybackState successfully'); + }).catch((err) => { + console.info(`setAVPlaybackState : ERROR : ${err.message}`); + }); +}); + +// Subscribe to the 'toggleFavorite' command event. +currentSession.on('toggleFavorite', (assetId) => { + console.log(`The application favorites ${assetId}.`); + // Perform the switch based on the last status. + let favorite = mediaFavorite == false ? true : false; + currentSession.setAVPlaybackState({isFavorite: favorite}).then(() => { + console.info('setAVPlaybackState successfully'); + }).catch((err) => { + console.info(`setAVPlaybackState : ERROR : ${err.message}`); + }); + mediaFavorite = favorite; +}); + +// Subscribe to the key event. +currentSession.on('handleKeyEvent', (event) => { + console.log(`User presses the key ${event.keyCode}`); +}); + +// Subscribe to output device changes. +currentSession.on('outputDeviceChange', (device) => { + console.log(`Output device changed to ${device.deviceName}`); +}); +``` + +5. Release resources. +```js +// Unsubscribe from the events. +currentSession.off('play'); +currentSession.off('pause'); +currentSession.off('stop'); +currentSession.off('playNext'); +currentSession.off('playPrevious'); +currentSession.off('fastForward'); +currentSession.off('rewind'); +currentSession.off('seek'); +currentSession.off('setSpeed'); +currentSession.off('setLoopMode'); +currentSession.off('toggleFavorite'); +currentSession.off('handleKeyEvent'); +currentSession.off('outputDeviceChange'); + +// Deactivate the session and destroy the object. +currentSession.deactivate().then(() => { + currentSession.destory(); +}); +``` + +### Verification +Touch the play, pause, or next button on the media application. Check whether the media playback state changes accordingly. + +### FAQs + +1. Session Service Exception +- Symptoms + + The session service is abnormal, and the application cannot obtain a response from the session service. For example, the session service is not running or the communication with the session service fails. The error message "Session service exception" is displayed. + +- Possible causes + + The session service is killed during session restart. + +- Solution + + (1) The system retries the operation automatically. If the error persists for 3 seconds or more, stop the operation on the session or controller. + + (2) Destroy the current session or session controller and re-create it. If the re-creation fails, stop the operation on the session. + +2. Session Does Not Exist +- Symptoms + + Parameters are set for or commands are sent to the session that does not exist. The error message "The session does not exist" is displayed. + +- Possible causes + + The session has been destroyed, and no session record exists on the server. + +- Solution + + (1) If the error occurs on the application, re-create the session. If the error occurs on Media Controller, stop sending query or control commands to the session. + + (2) If the error occurs on the session service, query the current session record and pass the correct session ID when creating the controller. + +3. Session Not Activated +- Symptoms + + A control command or event is sent to the session when it is not activated. The error message "The session not active" is displayed. + +- Possible causes + + The session is in the inactive state. + +- Solution + + Stop sending the command or event. Subscribe to the session activation status, and resume the sending when the session is activated. + +## Development for the Session Control End (Media Controller) + +### Basic Concepts +- Remote projection: A local media session is projected to a remote device. The local controller sends commands to control media playback on the remote device. +- Sending key events: The controller controls media playback by sending key events. +- Sending control commands: The controller controls media playback by sending control commands. +- Sending system key events: A system application calls APIs to send system key events to control media playback. +- Sending system control commands: A system application calls APIs to send system control commands to control media playback. + +### Available APIs + +The table below lists the APIs available for the development of the session control end. The APIs use either a callback or promise to return the result. The APIs listed below use a callback, which provide the same functions as their counterparts that use a promise. For details, see [AVSession Management](../reference/apis/js-apis-avsession.md). + +Table 2 Common APIs for session control end development + +| API | Description | +| ------------------------------------------------------------------------------------------------ | ----------------- | +| getAllSessionDescriptors(callback: AsyncCallback\>>): void | Obtains the descriptors of all sessions. | +| createController(sessionId: string, callback: AsyncCallback\): void | Creates a controller. | +| sendAVKeyEvent(event: KeyEvent, callback: AsyncCallback\): void | Sends a key event. | +| getLaunchAbility(callback: AsyncCallback\): void | Obtains the launcher ability. | +| sendControlCommand(command: AVControlCommand, callback: AsyncCallback\): void | Sends a control command. | +| sendSystemAVKeyEvent(event: KeyEvent, callback: AsyncCallback\): void | Send a system key event. | +| sendSystemControlCommand(command: AVControlCommand, callback: AsyncCallback\): void | Sends a system control command. | +| castAudio(session: SessionToken \| 'all', audioDevices: Array\, callback: AsyncCallback\): void | Casts the media session to a remote device.| + +### How to Develop +1. Import the modules. +```js +import avSession from '@ohos.multimedia.avsession'; +import {Action, KeyEvent} from '@ohos.multimodalInput.KeyEvent'; +import wantAgent from '@ohos.wantAgent'; +import audio from '@ohos.multimedia.audio'; +``` + +2. Obtain the session descriptors and create a controller. +```js +// Define global variables. +let g_controller = new Array(); +let g_centerSupportCmd:Set = new Set(['play', 'pause', 'playNext', 'playPrevious', 'fastForward', 'rewind', 'seek','setSpeed', 'setLoopMode', 'toggleFavorite']); +let g_validCmd:Set; + +// Obtain the session descriptors and create a controller. +avSession.getAllSessionDescriptors().then((descriptors) => { + descriptors.forEach((descriptor) => { + avSession.createController(descriptor.sessionId).then((controller) => { + g_controller.push(controller); + }).catch((err) => { + console.error('createController error'); + }); + }); +}).catch((err) => { + console.error('getAllSessionDescriptors error'); +}); + +// Subscribe to the 'sessionCreate' event and create a controller. +avSession.on('sessionCreate', (session) => { + // After a session is added, you must create a controller. + avSession.createController(session.sessionId).then((controller) => { + g_controller.push(controller); + }).catch((err) => { + console.info(`createController : ERROR : ${err.message}`); + }); +}); +``` + +3. Subscribe to the session state and service changes. +```js +// Subscribe to the 'activeStateChange' event. +controller.on('activeStateChange', (isActive) => { + if (isActive) { + console.log ("The widget corresponding to the controller is highlighted."); + } else { + console.log("The widget corresponding to the controller is invalid."); + } +}); + +// Subscribe to the 'sessionDestroy' event to enable Media Controller to get notified when the session dies. +controller.on('sessionDestroy', () => { + console.info('on sessionDestroy : SUCCESS '); + controller.destroy().then(() => { + console.info('destroy : SUCCESS '); + }).catch((err) => { + console.info(`destroy : ERROR :${err.message}`); + }); +}); + +// Subscribe to the 'sessionDestroy' event to enable the application to get notified when the session dies. +avSession.on('sessionDestroy', (session) => { + let index = g_controller.findIndex((controller) => { + return controller.sessionId == session.sessionId; + }); + if (index != 0) { + g_controller[index].destroy(); + g_controller.splice(index, 1); + } +}); + +// Subscribe to the 'topSessionChange' event. +avSession.on('topSessionChange', (session) => { + let index = g_controller.findIndex((controller) => { + return controller.sessionId == session.sessionId; + }); + // Place the session on the top. + if (index != 0) { + g_controller.sort((a, b) => { + return a.sessionId == session.sessionId ? -1 : 0; + }); + } +}); + +// Subscribe to the 'sessionServiceDie' event. +avSession.on('sessionServiceDie', () => { + // The server is abnormal, and the application clears resources. + console.log("Server exception"); +}) +``` + +4. Subscribe to media session information changes. +```js +// Subscribe to metadata changes. +let metaFilter = ['assetId', 'title', 'description']; +controller.on('metadataChange', metaFilter, (metadata) => { + console.info(`on metadataChange assetId : ${metadata.assetId}`); +}); + +// Subscribe to playback state changes. +let playbackFilter = ['state', 'speed', 'loopMode']; +controller.on('playbackStateChange', playbackFilter, (playbackState) => { + console.info(`on playbackStateChange state : ${playbackState.state}`); +}); + +// Subscribe to supported command changes. +controller.on('validCommandChange', (cmds) => { + console.info(`validCommandChange : SUCCESS : size : ${cmds.size}`); + console.info(`validCommandChange : SUCCESS : cmds : ${cmds.values()}`); + g_validCmd.clear(); + for (let c of g_centerSupportCmd) { + if (cmds.has(c)) { + g_validCmd.add(c); + } + } +}); + +// Subscribe to output device changes. +controller.on('outputDeviceChange', (device) => { + console.info(`on outputDeviceChange device isRemote : ${device.isRemote}`); +}); +``` + +5. Control the session behavior. +```js +// When the user touches the play button, the control command 'play' is sent to the session. +if (g_validCmd.has('play')) { + controller.sendControlCommand({command:'play'}).then(() => { + console.info('sendControlCommand successfully'); + }).catch((err) => { + console.info(`sendControlCommand : ERROR : ${err.message}`); + }); +} + +// When the user selects the single loop mode, the corresponding control command is sent to the session. +if (g_validCmd.has('setLoopMode')) { + controller.sendControlCommand({command: 'setLoopMode', parameter: avSession.LoopMode.LOOP_MODE_SINGLE}).then(() => { + console.info('sendControlCommand successfully'); + }).catch((err) => { + console.info(`sendControlCommand : ERROR : ${err.message}`); + }); +} + +// Send a key event. +let keyItem = {code: 0x49, pressedTime: 123456789, deviceId: 0}; +let event = {action: 2, key: keyItem, keys: [keyItem]}; +controller.sendAVKeyEvent(event).then(() => { + console.info('sendAVKeyEvent Successfully'); +}).catch((err) => { + console.info(`sendAVKeyEvent : ERROR : ${err.message}`); +}); + +// The user touches the blank area on the widget to start the application. +controller.getLaunchAbility().then((want) => { + console.log("Starting the application in the foreground"); +}).catch((err) => { + console.info(`getLaunchAbility : ERROR : ${err.message}`); +}); + +// Send the system key event. +let keyItem = {code: 0x49, pressedTime: 123456789, deviceId: 0}; +let event = {action: 2, key: keyItem, keys: [keyItem]}; +avSession.sendSystemAVKeyEvent(event).then(() => { + console.info('sendSystemAVKeyEvent Successfully'); +}).catch((err) => { + console.info(`sendSystemAVKeyEvent : ERROR : ${err.message}`); +}); + +// Send a system control command to the top session. +let avcommand = {command: 'toggleFavorite', parameter: "false"}; +avSession.sendSystemControlCommand(avcommand).then(() => { + console.info('sendSystemControlCommand successfully'); +}).catch((err) => { + console.info(`sendSystemControlCommand : ERROR : ${err.message}`); +}); + +// Cast the session to another device. +let audioManager = audio.getAudioManager(); +let audioDevices; +await audioManager.getDevices(audio.DeviceFlag.OUTPUT_DEVICES_FLAG).then((data) => { + audioDevices = data; + console.info('Promise returned to indicate that the device list is obtained.'); +}).catch((err) => { + console.info(`getDevices : ERROR : ${err.message}`); +}); + +avSession.castAudio('all', audioDevices).then(() => { + console.info('createController : SUCCESS'); +}).catch((err) => { + console.info(`createController : ERROR : ${err.message}`); +}); +``` + +6. Release resources. +```js +// Unsubscribe from the events. + controller.off('metadataChange'); + controller.off('playbackStateChange'); + controller.off('sessionDestroy'); + controller.off('activeStateChange'); + controller.off('validCommandChange'); + controller.off('outputDeviceChange'); + + // Destroy the controller. + controller.destroy().then(() => { + console.info('destroy : SUCCESS '); + }).catch((err) => { + console.info(`destroy : ERROR : ${err.message}`); + }); +``` + +### Verification +When you touch the play, pause, or next button in Media Controller, the playback state of the application changes accordingly. + +### FAQs +1. Controller Does Not Exist +- Symptoms + + A control command or an event is sent to the controller that does not exist. The error message "The session controller does not exist" is displayed. + +- Possible causes + + The controller has been destroyed. + +- Solution + + Query the session record and create the corresponding controller. + +2. Remote Session Connection Failure +- Symptoms + + The communication between the local session and the remote session fails. The error information "The remote session connection failed" is displayed. + +- Possible causes + + The communication between devices is interrupted. + +- Solution + + Stop sending control commands to the session. Subscribe to output device changes, and resume the sending when the output device is changed. + +3. Invalid Session Command +- Symptoms + + The control command or event sent to the session is not supported. The error message "Invalid session command" is displayed. + +- Possible causes + + The session does not support this command. + +- Solution + + Stop sending the command or event. Query the commands supported by the session, and send a command supported. + +4. Too Many Commands or Events +- Symptoms + + The session client sends too many messages or commands to the server in a period of time, causing the server to be overloaded. The error message "Command or event overload" is displayed. + +- Possible causes + + The server is overloaded with messages or events. + +- Solution + + Control the frequency of sending commands or events. diff --git a/en/application-dev/media/avsession-overview.md b/en/application-dev/media/avsession-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..761483bf5052ef48cd9313261ead681b295d6604 --- /dev/null +++ b/en/application-dev/media/avsession-overview.md @@ -0,0 +1,52 @@ +# AVSession Overview + +## Overview + + AVSession, short for audio and video session, is also known as media session. + - Application developers can use the APIs provided by the **AVSession** module to connect their audio and video applications to the system's Media Controller. + - System developers can use the APIs provided by the **AVSession** module to display media information of system audio and video applications and carry out unified playback control. + + You can implement the following features through the **AVSession** module: + + 1. Unified playback control entry + + If there are multiple audio and video applications on the device, users need to switch to and access different applications to control media playback. With AVSession, a unified playback control entry of the system (such as Media Controller) is used for playback control of these audio and video applications. No more switching is required. + + 2. Better background application management + + When an application running in the background automatically starts audio playback, it is difficult for users to locate the application. With AVSession, users can quickly find the application that plays the audio clip in Media Controller. + +## Basic Concepts + +- AVSession + + A channel used for information exchange between applications and Media Controller. For AVSession, one end is the media application under control, and the other end is Media Controller. Through AVSession, an application can transfer the media playback information to Media Controller and receive control commands from Media Controller. + +- AVSessionController + + Object that controls media sessions and thereby controls the playback behavior of applications. Through AVSessionController, Media Controller can control the playback behavior of applications, obtain playback information, and send control commands. It can also monitor the playback state of applications to ensure synchronization of the media session information. + +- Media Controller + + Holder of AVSessionController. Through AVSessionController, Media Controller sends commands to control media playback of applications. + +## Implementation Principle + +The **AVSession** module provides two classes: **AVSession** and **AVSessionController**. + +**Figure 1** AVSession interaction + +![en-us_image_avsession](figures/en-us_image_avsession.png) + +- Interaction between the application and Media Controller: First, an audio application creates an **AVSession** object and sets session information, including media metadata, launcher ability, and playback state information. Then, Media Controller creates an **AVSessionController** object to obtain session-related information and send the 'play' command to the audio application. Finally, the audio application responds to the command and updates the playback state. + +- Distributed projection: When a connected device creates a local session, Media Controller or the audio application can select another device to be projected based on the device list, synchronize the local session to the remote device, and generate a controllable remote session. The remote session is controlled by sending control commands to the remote device's application through its AVSessionController. + +## Constraints + +- The playback information displayed in Media Controller is the media information proactively written by the media application to AVSession. +- Media Controller controls the playback of a media application based on the responses of the media application to control commands. +- AVSession can transmit media playback information and control commands. It does not display information or execute control commands. +- Do not develop Media Controller for common applications. For common audio and video applications running on OpenHarmony, the default control end is Media Controller, which is a system application. You do not need to carry out additional development for Media Controller. +- If you want to develop your own system running OpenHarmony, you can develop your own Media Controller. +- For better background management of audio and video applications, the **AVSession** module enforces background control for third-party applications. Only third-party applications that have accessed AVSession can play audio in the background. Otherwise, the system forcibly pauses the playback when a third-party application switches to the background. diff --git a/en/application-dev/media/camera.md b/en/application-dev/media/camera.md index 06439dd049be835cdf5a96a35e2a2a42012ee6f8..8032348105eb70a3b5dbfd431de3632d6d04cb8a 100644 --- a/en/application-dev/media/camera.md +++ b/en/application-dev/media/camera.md @@ -2,7 +2,13 @@ ## When to Use -You can use the camera module to develop basic camera functions, including previewing, photographing, and video recording. +With the APIs provided by the **Camera** module, you can access and operate camera devices and develop new functions. Common operations include preview, photographing, and video recording. You can also implement flash control, exposure time control, focus mode control, zooming control, and many others. + +Before calling camera APIs, be familiar with the following concepts: + +- **Static camera capabilities**: A series of parameters used to describe inherent capabilities of a camera, such as orientation and supported resolution. +- **Physical camera**: An independent camera device. The physical camera ID is a string that uniquely identifies a physical camera. +- **Asynchronous operation**: To prevent the UI thread from being blocked, most **Camera** calls are asynchronous. Each API provides the callback and promise functions. ## How to Develop @@ -12,152 +18,301 @@ For details about the APIs, see [Camera Management](../reference/apis/js-apis-ca ### Full-Process Scenario -The full process includes creating an instance, setting parameters, managing sessions, taking photos, recording videos, and releasing resources. +The full process includes applying for permissions, creating an instance, setting parameters, managing sessions, taking photos, recording videos, and releasing resources. + +#### Applying for Permissions + +You must apply for the permission for your application to access the camera device and other functions. The following table lists camera-related permissions. + +| Permission| Attribute Value | +| -------- | ------------------------------ | +| Camera| ohos.permission.CAMERA | +| Call recording| ohos.permission.MICROPHONE | +| Storage| ohos.permission.WRITE_MEDIA | +| Read| ohos.permission.READ_MEDIA | +| Location| ohos.permission.MEDIA_LOCATION | -The method for creating an XComponent is also provided. For details, see [XComponent Creation](#xcomponent-creation). +The code snippet is as follows: -For details about the APIs used to save images, see [Image Processing](../reference/apis/js-apis-image.md). +```typescript +const PERMISSIONS: Array = [ + 'ohos.permission.CAMERA', + 'ohos.permission.MICROPHONE', + 'ohos.permission.MEDIA_LOCATION', + 'ohos.permission.READ_MEDIA', + 'ohos.permission.WRITE_MEDIA' +] + +function applyPermission() { + console.info('[permission] get permission'); + globalThis.abilityContext.requestPermissionFromUser(PERMISSIONS) + } +``` #### Creating an Instance -```js +You must create an independent **CameraManager** instance before performing camera operations. If this operation fails, the camera may be occupied or unusable. If the camera is occupied, wait until it is released. You can call **getSupportedCameras()** to obtain the list of cameras supported by the current device. The list stores all camera IDs of the current device. If the list is not empty, each ID in the list can be used to create an independent camera instance. If the list is empty, no camera is available for the current device and subsequent operations cannot be performed. The camera has preview, shooting, video recording, and metadata streams. You can use **getSupportedOutputCapability()** to obtain the output stream capabilities of the camera and configure them in the **profile** field in **CameraOutputCapability**. The procedure for creating a **CameraManager** instance is as follows: + +```typescript import camera from '@ohos.multimedia.camera' import image from '@ohos.multimedia.image' import media from '@ohos.multimedia.media' -import featureAbility from '@ohos.ability.featureAbility' // Create a CameraManager object. -let cameraManager -await camera.getCameraManager(globalThis.Context, (err, manager) => { - if (err) { - console.error('Failed to get the CameraManager instance ${err.message}'); - return; - } - console.log('Callback returned with the CameraManager instance'); - cameraManager = manager -}) - -// Register a callback to listen for camera status changes and obtain the updated camera status information. -cameraManager.on('cameraStatus', (cameraStatusInfo) => { - console.log('camera : ' + cameraStatusInfo.camera.cameraId); - console.log('status: ' + cameraStatusInfo.status); -}) +context: any = getContext(this) +let cameraManager = await camera.getCameraManager(this.context) +if (!cameraManager) { + console.error('Failed to get the CameraManager instance'); +} // Obtain the camera list. -let cameraArray -await cameraManager.getCameras((err, cameras) => { - if (err) { - console.error('Failed to get the cameras. ${err.message}'); - return; - } - console.log('Callback returned with an array of supported cameras: ' + cameras.length); - cameraArray = cameras -}) +let cameraArray = await cameraManager.getSupportedCameras() +if (!cameraArray) { + console.error('Failed to get the cameras'); +} -for(let cameraIndex = 0; cameraIndex < cameraArray.length; cameraIndex++) { - console.log('cameraId : ' + cameraArray[cameraIndex].cameraId) // Obtain the camera ID. - console.log('cameraPosition : ' + cameraArray[cameraIndex].cameraPosition) // Obtain the camera position. - console.log('cameraType : ' + cameraArray[cameraIndex].cameraType) // Obtain the camera type. - console.log('connectionType : ' + cameraArray[cameraIndex].connectionType) // Obtain the camera connection type. +for (let index = 0; index < cameraArray.length; index++) { + console.log('cameraId : ' + cameraArray[index].cameraId) // Obtain the camera ID. + console.log('cameraPosition : ' + cameraArray[index].cameraPosition) // Obtain the camera position. + console.log('cameraType : ' + cameraArray[index].cameraType) // Obtain the camera type. + console.log('connectionType : ' + cameraArray[index].connectionType) // Obtain the camera connection type. } // Create a camera input stream. -let cameraInput -await cameraManager.createCameraInput(cameraArray[0].cameraId).then((input) => { - console.log('Promise returned with the CameraInput instance'); - cameraInput = input -}) +let cameraInput = await cameraManager.createCameraInput(cameraArray[0]) -// Create a preview output stream. -let previewOutput -camera.createPreviewOutput((globalThis.surfaceId), (err, output) => { - if (err) { - console.error('Failed to create the PreviewOutput instance. ${err.message}'); - return; - } - console.log('Callback returned with previewOutput instance'); - previewOutput = output -}); +// Open camera +await cameraInput.open(); + +// Obtain the output stream capabilities supported by the camera. +let cameraOutputCap = await cameraManager.getSupportedOutputCapability(cameraArray[0]); +if (!cameraOutputCap) { + console.error("outputCapability outputCapability == null || undefined") +} else { + console.info("outputCapability: " + JSON.stringify(cameraOutputCap)); +} + +let previewProfilesArray = cameraOutputCap.GetPreviewProfiles(); +if (!previewProfilesArray) { + console.error("createOutput previewProfilesArray == null || undefined") +} + +let photoProfilesArray = cameraOutputCap.GetPhotoProfiles(); +if (!photoProfilesArray) { + console.error("createOutput photoProfilesArray == null || undefined") +} + +let videoProfilesArray = cameraOutputCap.GetVideoProfiles(); +if (!videoProfilesArray) { + console.error("createOutput videoProfilesArray == null || undefined") +} + +let metadataObjectTypesArray = cameraOutputCap.GetSupportedMetadataObjectType(); +if (!metadataObjectTypesArray) { + console.error("createOutput metadataObjectTypesArray == null || undefined") +} -// Create an ImageReceiver object and set image parameters. +// Create a preview stream. For details about the surfaceId parameter, see the XComponent section. The preview stream is the surface provided by the XComponent. +let previewOutput = await cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId) +if (!previewOutput) { + console.error("Failed to create the PreviewOutput instance.") +} + +// Create an ImageReceiver object and set photo parameters. The resolution is set based on the photographing resolutions supported by the current device, which are obtained by photoProfilesArray. let imageReceiver = await image.createImageReceiver(1920, 1080, 4, 8) // Obtain the surface ID for displaying the photos. let photoSurfaceId = await imageReceiver.getReceivingSurfaceId() // Create a photographing output stream. -let photoOutput -camera.createPhotoOutput((photoSurfaceId), (err, output) => { - if (err) { - console.error('Failed to create the PhotoOutput instance. ${err.message}'); - return; - } - console.log('Callback returned with the PhotoOutput instance.'); - photoOutput = output -}); +let photoOutput = await cameraManager.createPhotoOutput(photoProfilesArray[0], photoSurfaceId) +if (!photoOutput) { + console.error('Failed to create the PhotoOutput instance.'); + return; +} // Define video recording parameters. -let videoProfile = { - audioBitrate : 48000, - audioChannels : 2, - audioCodec : 'audio/mp4a-latm', - audioSampleRate : 48000, - fileFormat : 'mp4', - videoBitrate : 48000, - videoCodec : 'video/mp4v-es', - videoFrameWidth : 640, - videoFrameHeight : 480, - videoFrameRate : 30 -} let videoConfig = { - audioSourceType : 1, - videoSourceType : 0, - profile : videoProfile, - url : 'file:///data/media/01.mp4', - orientationHint : 0, - location : { latitude : 30, longitude : 130 }, + audioSourceType: 1, + videoSourceType: 1, + profile: { + audioBitrate: 48000, + audioChannels: 2, + audioCodec: 'audio/mp4v-es', + audioSampleRate: 48000, + durationTime: 1000, + fileFormat: 'mp4', + videoBitrate: 48000, + videoCodec: 'video/mp4v-es', + videoFrameWidth: 640, + videoFrameHeight: 480, + videoFrameRate: 30 + }, + url: 'file:///data/media/01.mp4', + orientationHint: 0, + maxSize: 100, + maxDuration: 500, + rotation: 0 } // Create a video recording output stream. let videoRecorder -await media.createVideoRecorder().then((recorder) => { +media.createVideoRecorder().then((recorder) => { console.log('createVideoRecorder called') videoRecorder = recorder }) // Set video recording parameters. -await videoRecorder.prepare(videoConfig) +videoRecorder.prepare(videoConfig) // Obtain the surface ID for video recording. -await videoRecorder.getInputSurface().then((id) => { +let videoSurfaceId +videoRecorder.getInputSurface().then((id) => { console.log('getInputSurface called') videoSurfaceId = id }) -``` -For details about how to create a video recorder, see [Video Recording Development](./video-recorder.md). -```js + // Create a VideoOutput object. -let videoOutput -camera.createVideoOutput((surfaceId), (err, output) => { - if (err) { - console.error('Failed to create the VideoOutput instance. ${err.message}'); - return; +let videoOutput = await cameraManager.createVideoOutput(videoProfilesArray[0], videoSurfaceId) +if (!videoOutput) { + console.error('Failed to create the videoOutput instance.'); + return; +} +``` +Surfaces must be created in advance for the preview, shooting, and video recording stream. The preview stream is the surface provided by the **XComponent**, the shooting stream is the surface provided by **ImageReceiver**, and the video recording stream is the surface provided by **VideoRecorder**. + +**XComponent** + +```typescript +mXComponentController: XComponentController = new XComponentController // Create an XComponentController. + +build() { + Flex() { + XComponent({ // Create an XComponent. + id: '', + type: 'surface', + libraryname: '', + controller: this.mXComponentController + }) + .onload(() => { // Set the onload callback. + // Set the surface width and height (1920 x 1080). For details about how to set the preview size, see the preview resolutions supported by the current device, which are obtained by previewProfilesArray. + this.mXComponentController.setXComponentSurfaceSize({surfaceWidth:1920,surfaceHeight:1080}) + // Obtain the surface ID. + globalThis.surfaceId = mXComponentController.getXComponentSurfaceId() + }) + .width('1920px') // Set the width of the XComponent. + .height('1080px') // Set the height of the XComponent. } - console.log('Callback returned with the VideoOutput instance'); - videoOutput = output -}); +} +``` +**ImageReceiver** + +```typescript +function getImageReceiverSurfaceId() { + let receiver = image.createImageReceiver(640, 480, 4, 8) + console.log(TAG + 'before ImageReceiver check') + if (receiver !== undefined) { + console.log('ImageReceiver is ok') + surfaceId1 = receiver.getReceivingSurfaceId() + console.log('ImageReceived id: ' + JSON.stringify(surfaceId1)) + } else { + console.log('ImageReceiver is not ok') + } + } +``` + +**VideoRecorder** + +```typescript +function getVideoRecorderSurface() { + await getFd('CameraManager.mp4'); + mVideoConfig.url = mFdPath; + media.createVideoRecorder((err, recorder) => { + console.info('Entering create video receiver') + mVideoRecorder = recorder + console.info('videoRecorder is :' + JSON.stringify(mVideoRecorder)) + console.info('videoRecorder.prepare called.') + mVideoRecorder.prepare(mVideoConfig, (err) => { + console.info('videoRecorder.prepare success.') + mVideoRecorder.getInputSurface((err, id) => { + console.info('getInputSurface called') + mVideoSurface = id + console.info('getInputSurface surfaceId: ' + JSON.stringify(mVideoSurface)) + }) + }) + }) + } +``` + +#### Managing Sessions + +##### Creating a Session + +```typescript +// Create a session. +let captureSession = await camera.createCaptureSession() +if (!captureSession) { + console.error('Failed to create the CaptureSession instance.'); + return; +} +console.log('Callback returned with the CaptureSession instance.' + session); + +// Start configuration for the session. +await captureSession.beginConfig() + +// Add the camera input stream to the session. +await captureSession.addInput(cameraInput) + +// Add the preview input stream to the session. +await captureSession.addOutput(previewOutput) + +// Add the photographing output stream to the session. +await captureSession.addOutput(photoOutput) + +// Commit the session configuration. +await captureSession.commitConfig() + +// Start the session. +await captureSession.start().then(() => { + console.log('Promise returned to indicate the session start success.'); +}) +``` + +##### Switching a Session + +```typescript +// Stop the session. +await captureSession.stop() + +// Start configuration for the session. +await captureSession.beginConfig() + +// Remove the photographing output stream from the session. +await captureSession.removeOutput(photoOutput) + +// Add a video recording output stream to the session. +await captureSession.addOutput(videoOutput) + +// Commit the session configuration. +await captureSession.commitConfig() + +// Start the session. +await captureSession.start().then(() => { + console.log('Promise returned to indicate the session start success.'); +}) ``` #### Setting Parameters -```js +```typescript // Check whether the camera has flash. -let flashStatus -await cameraInput.hasFlash().then((status) => { - console.log('Promise returned with the flash light support status:' + status); - flashStatus = status -}) -if(flashStatus) { +let flashStatus = await captureSession.hasFlash() +if (!flashStatus) { + console.error('Failed to check whether the device has the flash mode.'); +} +console.log('Promise returned with the flash light support status:' + flashStatus); + +if (flashStatus) { // Check whether the auto flash mode is supported. let flashModeStatus - cameraInput.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO, (err, status) => { + captureSession.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO, async (err, status) => { if (err) { console.error('Failed to check whether the flash mode is supported. ${err.message}'); return; @@ -167,7 +322,7 @@ if(flashStatus) { }) if(flashModeStatus) { // Set the flash mode to auto. - cameraInput.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO, (err) => { + captureSession.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO, async (err) => { if (err) { console.error('Failed to set the flash mode ${err.message}'); return; @@ -179,7 +334,7 @@ if(flashStatus) { // Check whether the continuous auto focus is supported. let focusModeStatus -cameraInput.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, (err, status) => { +captureSession.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, async (err, status) => { if (err) { console.error('Failed to check whether the focus mode is supported. ${err.message}'); return; @@ -187,9 +342,9 @@ cameraInput.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, (e console.log('Callback returned with the focus mode support status: ' + status); focusModeStatus = status }) -if(focusModeStatus) { +if (focusModeStatus) { // Set the focus mode to continuous auto focus. - cameraInput.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, (err) => { + captureSession.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, async (err) => { if (err) { console.error('Failed to set the focus mode ${err.message}'); return; @@ -199,18 +354,14 @@ if(focusModeStatus) { } // Obtain the zoom ratio range supported by the camera. -let zoomRatioRange -cameraInput.getZoomRatioRange((err, range) => { - if (err) { - console.error('Failed to get the zoom ratio range. ${err.message}'); - return; - } - console.log('Callback returned with zoom ratio range: ' + range.length); - zoomRatioRange = range -}) +let zoomRatioRange = await captureSession.getZoomRatioRange() +if (!zoomRatioRange) { + console.error('Failed to get the zoom ratio range.'); + return; +} // Set a zoom ratio. -cameraInput.setZoomRatio(zoomRatioRange[0], (err) => { +captureSession.setZoomRatio(zoomRatioRange[0], async (err) => { if (err) { console.error('Failed to set the zoom ratio value ${err.message}'); return; @@ -219,139 +370,15 @@ cameraInput.setZoomRatio(zoomRatioRange[0], (err) => { }) ``` -#### Managing Sessions - -##### Creating a Session - -```js -// Create a Context object. -let context = featureAbility.getContext() - -// Create a session. -let captureSession -await camera.createCaptureSession((context), (err, session) => { - if (err) { - console.error('Failed to create the CaptureSession instance. ${err.message}'); - return; - } - console.log('Callback returned with the CaptureSession instance.' + session); - captureSession = session -}); - -// Start configuration for the session. -await captureSession.beginConfig((err) => { - if (err) { - console.error('Failed to start the configuration. ${err.message}'); - return; - } - console.log('Callback invoked to indicate the begin config success.'); -}); - -// Add the camera input stream to the session. -await captureSession.addInput(cameraInput, (err) => { - if (err) { - console.error('Failed to add the CameraInput instance. ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the CameraInput instance is added.'); -}); - -// Add the preview input stream to the session. -await captureSession.addOutput(previewOutput, (err) => { - if (err) { - console.error('Failed to add the PreviewOutput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the PreviewOutput instance is added.'); -}); - -// Add the photographing output stream to the session. -await captureSession.addOutput(photoOutput, (err) => { - if (err) { - console.error('Failed to add the PhotoOutput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the PhotoOutput instance is added.'); -}); - -// Commit the session configuration. -await captureSession.commitConfig((err) => { - if (err) { - console.error('Failed to commit the configuration. ${err.message}'); - return; - } - console.log('Callback invoked to indicate the commit config success.'); -}); - -// Start the session. -await captureSession.start().then(() => { - console.log('Promise returned to indicate the session start success.'); -}) -``` - -##### Switching a Session - -```js -// Stop the session. -await captureSession.stop((err) => { - if (err) { - console.error('Failed to stop the session ${err.message}'); - return; - } - console.log('Callback invoked to indicate the session stop success.'); -}); - -// Start configuration for the session. -await captureSession.beginConfig((err) => { - if (err) { - console.error('Failed to start the configuration. ${err.message}'); - return; - } - console.log('Callback invoked to indicate the begin config success.'); -}); - -// Remove the photographing output stream from the session. -await captureSession.removeOutput(photoOutput, (err) => { - if (err) { - console.error('Failed to remove the PhotoOutput instance. ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the PhotoOutput instance is removed.'); -}); - -// Add a video recording output stream to the session. -await captureSession.addOutput(videoOutput, (err) => { - if (err) { - console.error('Failed to add the VideoOutput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the VideoOutput instance is added.'); -}); - -// Commit the session configuration. -await captureSession.commitConfig((err) => { - if (err) { - console.error('Failed to commit the configuration. ${err.message}'); - return; - } - console.log('Callback invoked to indicate the commit config success.'); -}); - -// Start the session. -await captureSession.start().then(() => { - console.log('Promise returned to indicate the session start success.'); -}) -``` - #### Taking Photos -```js +```typescript let settings = { quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // Set the image quality to high. rotation: camera.ImageRotation.ROTATION_0 // Set the image rotation angle to 0. } // Use the current photographing settings to take photos. -photoOutput.capture(settings, (err) => { +photoOutput.capture(settings, async (err) => { if (err) { console.error('Failed to capture the photo ${err.message}'); return; @@ -362,9 +389,9 @@ photoOutput.capture(settings, (err) => { #### Recording Videos -```js +```typescript // Start the video recording output stream. -videoOutput.start((err) => { +videoOutput.start(async (err) => { if (err) { console.error('Failed to start the video output ${err.message}'); return; @@ -373,17 +400,17 @@ videoOutput.start((err) => { }); // Start video recording. -await videoRecorder.start().then(() => { +videoRecorder.start().then(() => { console.info('videoRecorder start success'); } // Stop video recording. -await videoRecorder.stop().then(() => { +videoRecorder.stop().then(() => { console.info('stop success'); } // Stop the video recording output stream. -await videoOutput.stop((err) => { +videoOutput.stop((err) => { if (err) { console.error('Failed to stop the video output ${err.message}'); return; @@ -392,81 +419,34 @@ await videoOutput.stop((err) => { }); ``` +For details about the APIs used for saving photos, see [Image Processing](image.md#using-imagereceiver). + #### Releasing Resources -```js +```typescript // Stop the session. -await captureSession.stop((err) => { - if (err) { - console.error('Failed to stop the session ${err.message}'); - return; - } - console.log('Callback invoked to indicate the session stop success.'); -}); +captureSession.stop() + // Release the camera input stream. -await cameraInput.release((err) => { - if (err) { - console.error('Failed to release the CameraInput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the CameraInput instance is released successfully.'); -}); +cameraInput.release() + // Release the preview output stream. -await previewOutput.release((err) => { - if (err) { - console.error('Failed to release the PreviewOutput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the PreviewOutput instance is released successfully.'); -}); +previewOutput.release() + // Release the photographing output stream. -await photoOutput.release((err) => { - if (err) { - console.error('Failed to release the PhotoOutput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the PhotoOutput instance is released successfully.'); -}); +photoOutput.release() + // Release the video recording output stream. -await videoOutput.release((err) => { - if (err) { - console.error('Failed to release the VideoOutput instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the VideoOutput instance is released successfully.'); -}); +videoOutput.release() + // Release the session. -await captureSession.release((err) => { - if (err) { - console.error('Failed to release the CaptureSession instance ${err.message}'); - return; - } - console.log('Callback invoked to indicate that the CaptureSession instance is released successfully.'); -}); -``` +captureSession.release() -#### XComponent Creation -The surface ID must be obtained for image preview. +// Set the session to null. +captureSession = null +``` -```js -mXComponentController: XComponentController = new XComponentController // Create an XComponentController. +## Process Flowchart -build() { - Flex() { - XComponent({ // Create an XComponent. - id: '', - type: 'surface', - libraryname: '', - controller: this.mXComponentController - }) - .onload(() => { // Set the onload callback. - // Set the width and height of the surface to 1920 and 1080, respectively. - this.mXComponentController.setXComponentSurfaceSize({surfaceWidth:1920,surfaceHeight:1080}) - // Obtain the surface ID. - globalThis.surfaceId = mXComponentController.getXComponentSurfaceId() - }) - .width('1920px') // Set the width of the XComponent. - .height('1080px') // Set the height of the XComponent. - } -} -``` +The following figure shows the process of using the camera. +![camera_framework process](figures/camera_framework_process.jpg) diff --git a/en/application-dev/media/figures/camera_framework_process.jpg b/en/application-dev/media/figures/camera_framework_process.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1207a9a4adb5d5886f9427b07f0ec7d717fc5bf8 Binary files /dev/null and b/en/application-dev/media/figures/camera_framework_process.jpg differ diff --git a/en/application-dev/media/figures/en-us_image_audio_routing_manager.png b/en/application-dev/media/figures/en-us_image_audio_routing_manager.png new file mode 100644 index 0000000000000000000000000000000000000000..710679f6cac0c30d06dffa97b0e80b3cebe80f79 Binary files /dev/null and b/en/application-dev/media/figures/en-us_image_audio_routing_manager.png differ diff --git a/en/application-dev/media/figures/en-us_image_audio_state_machine.png b/en/application-dev/media/figures/en-us_image_audio_state_machine.png index 7497edd0edbdcfccbc448e9f2f48268ebb75e72e..22b7aeaa1db5b369d3daf44854d7f7f9a00f775b 100644 Binary files a/en/application-dev/media/figures/en-us_image_audio_state_machine.png and b/en/application-dev/media/figures/en-us_image_audio_state_machine.png differ diff --git a/en/application-dev/media/figures/en-us_image_audio_volume_manager.png b/en/application-dev/media/figures/en-us_image_audio_volume_manager.png new file mode 100644 index 0000000000000000000000000000000000000000..0d47fbfacce9c1ff48811e1cf5d764231bdb596b Binary files /dev/null and b/en/application-dev/media/figures/en-us_image_audio_volume_manager.png differ diff --git a/en/application-dev/media/figures/en-us_image_avsession.png b/en/application-dev/media/figures/en-us_image_avsession.png new file mode 100644 index 0000000000000000000000000000000000000000..3289bc4ca3c54eb3e99c9230c821380f8f7c0c5b Binary files /dev/null and b/en/application-dev/media/figures/en-us_image_avsession.png differ diff --git a/en/application-dev/media/image.md b/en/application-dev/media/image.md index 8e6eca83375ea64b2948325fc1f7bf7f28746767..048716dfdcd76d0e35f4ed3ad70a5eeb266ac8cc 100644 --- a/en/application-dev/media/image.md +++ b/en/application-dev/media/image.md @@ -21,45 +21,47 @@ let opts = { alphaType: 0, editable: true, pixelFormat: 4, scaleMode: 1, size: { // Create a PixelMap object. const color = new ArrayBuffer(96); let opts = { alphaType: 0, editable: true, pixelFormat: 4, scaleMode: 1, size: { height: 2, width: 3 } } - image.createPixelMap(color, opts, pixelmap => { - expect(pixelmap !== null).assertTrue(); - console.info('TC_001-1 success'); - done(); - }) +image.createPixelMap(color, opts, (err, pixelmap) => { + console.log('Succeeded in creating pixelmap.'); +}) + // Read pixels. -pixelmap.readPixels(area,(data) => { - if(data !== null) { - var bufferArr = new Uint8Array(area.pixels); - var res = true; - for (var i = 0; i < bufferArr.length; i++) { - console.info('TC_021-1 buffer ' + bufferArr[i]); - if(res) { - if(bufferArr[i] == 0) { - res = false; - console.info('TC_021-1 Success'); - expect(true).assertTrue(); - done(); - break; - } - } - } +const area = { + pixels: new ArrayBuffer(8), + offset: 0, + stride: 8, + region: { size: { height: 1, width: 2 }, x: 0, y: 0 } +} +pixelmap.readPixels(area,() => { + var bufferArr = new Uint8Array(area.pixels); + var res = true; + for (var i = 0; i < bufferArr.length; i++) { + console.info(' buffer ' + bufferArr[i]); + if(res) { + if(bufferArr[i] == 0) { + res = false; + console.log('readPixels end.'); + break; + } + } + } +}) // Store pixels. const readBuffer = new ArrayBuffer(96); pixelmap.readPixelsToBuffer(readBuffer,() => { -var bufferArr = new Uint8Array(readBuffer); -var res = true; -for (var i = 0; i < bufferArr.length; i++) { - if(res) { - if (bufferArr[i] !== 0) { - res = false; - console.info('TC_020-1 Success'); - expect(true).assertTrue(); - done(); - break; + var bufferArr = new Uint8Array(readBuffer); + var res = true; + for (var i = 0; i < bufferArr.length; i++) { + if(res) { + if (bufferArr[i] !== 0) { + res = false; + console.log('readPixelsToBuffer end.'); + break; + } } } -} +}) // Write pixels. pixelmap.writePixels(area,() => { @@ -71,56 +73,51 @@ pixelmap.writePixels(area,() => { if(res) { if (readArr[i] !== 0) { res = false; - console.info('TC_022-1 Success'); - expect(true).assertTrue(); - done(); + console.log('readPixels end.please check buffer'); break; } } } + }) +}) // Write pixels to the buffer. pixelmap.writeBufferToPixels(writeColor).then(() => { const readBuffer = new ArrayBuffer(96); pixelmap.readPixelsToBuffer(readBuffer).then (() => { - var bufferArr = new Uint8Array(readBuffer); - var res = true; - for (var i = 0; i < bufferArr.length; i++) { - if(res) { - if (bufferArr[i] !== i) { - res = false; - console.info('TC_023 Success'); - expect(true).assertTrue() - done(); + var bufferArr = new Uint8Array(readBuffer); + var res = true; + for (var i = 0; i < bufferArr.length; i++) { + if(res) { + if (bufferArr[i] !== i) { + res = false; + console.log('readPixels end.please check buffer'); break; } } } + }) +}) // Obtain image information. -pixelmap.getImageInfo( imageInfo => { +pixelmap.getImageInfo((error, imageInfo) => { if (imageInfo !== null) { - console.info('TC_024-1 imageInfo is ready'); - expect(imageInfo.size.height == 4).assertTrue(); - expect(imageInfo.size.width == 6).assertTrue(); - expect(imageInfo.pixelFormat == 4).assertTrue(); - done(); + console.log('Succeeded in getting imageInfo'); } }) // Release the PixelMap object. pixelmap.release(()=>{ - expect(true).assertTrue(); - console.log('TC_027-1 suc'); - done(); + console.log('Succeeded in releasing pixelmap'); }) -let path = '/data/local/tmp/test.jpg'; // Create an image source (uri). -const imageSourceApi = image.createImageSource(path); // '/data/local/tmp/test.jpg' +let path = '/data/local/tmp/test.jpg'; +const imageSourceApi = image.createImageSource(path); // Create an image source (fd). -const imageSourceApi = image.createImageSource(29); +let fd = 29; +const imageSourceApi = image.createImageSource(fd); // Create an image source (data). const data = new ArrayBuffer(96); @@ -128,15 +125,15 @@ const imageSourceApi = image.createImageSource(data); // Release the image source. imageSourceApi.release(() => { - console.info('TC_044-1 Success'); - }) + console.log('Succeeded in releasing imagesource'); +}) // Encode the image. const imagePackerApi = image.createImagePacker(); -imagePackerApi.packing(imageSourceApi, packOpts, data => { - console.info('TC_062-1 finished'); - expect(data !== null).assertTrue(); - done(); +const imageSourceApi = image.createImageSource(0); +let packOpts = { format:"image/jpeg", quality:98 }; +imagePackerApi.packing(imageSourceApi, packOpts, (err, data) => { + console.log('Succeeded in packing'); }) // Release the ImagePacker object. @@ -163,60 +160,37 @@ let decodingOptions = { }; // Create a pixel map in callback mode. -imageSourceApi.createPixelMap(decodingOptions, pixelmap => { - console.info('TC_050 createPixelMap '); - expect(pixelmap !== null ).assertTrue(); - done(); - }) -} +imageSourceApi.createPixelMap(decodingOptions, (err, pixelmap) => { + console.log('Succeeded in creating pixelmap.'); +}) // Create a pixel map in promise mode. imageSourceApi.createPixelMap().then(pixelmap => { - console.info('TC_050-11 createPixelMap '); - expect(pixelmap !== null ).assertTrue(); - done(); + console.log('Succeeded in creating pixelmap.'); }) // Capture error information when an exception occurs during function invoking. catch(error => { - console.log('TC_050-11 error: ' + error); - expect().assertFail(); - done(); + console.log('Failed in creating pixelmap.' + error); }) // Obtain the number of bytes in each line of pixels. -pixelmap.getBytesNumberPerRow( num => { - console.info('TC_025-1 num is ' + num); - expect(num == expectNum).assertTrue(); - done(); -}) +var num = pixelmap.getBytesNumberPerRow(); // Obtain the total number of pixel bytes. -pixelmap.getPixelBytesNumber(num => { - console.info('TC_026-1 num is ' + num); - expect(num == expectNum).assertTrue(); - done(); -}) +var pixelSize = pixelmap.getPixelBytesNumber(); // Obtain the pixel map information. -pixelmap.getImageInfo( imageInfo => {}) - -// Print the failure information. -console.info('TC_024-1 imageInfo is empty'); -expect(false).assertTrue() +pixelmap.getImageInfo().then( imageInfo => {}); // Release the PixelMap object. pixelmap.release(()=>{ - expect(true).assertTrue(); - console.log('TC_027-1 suc'); - done(); + console.log('Succeeded in releasing pixelmap'); }) // Capture release failure information. catch(error => { - console.log('TC_027-1 error: ' + error); - expect().assertFail(); - done(); + console.log('Failed in releasing pixelmap.' + error); }) ``` @@ -230,9 +204,7 @@ const imageSourceApi = image.createImageSource(path); // '/data/local/tmp/test.p // Print the error message if the image source fails to be created. if (imageSourceApi == null) { - console.info('TC_062 create image source failed'); - expect(false).assertTrue(); - done(); + console.log('Failed in creating imageSource.'); } // Create an image packer if the image source is successfully created. @@ -240,9 +212,7 @@ const imagePackerApi = image.createImagePacker(); // Print the error information if the image packer fails to be created. if (imagePackerApi == null) { - console.info('TC_062 create image packer failed'); - expect(false).assertTrue(); - done(); + console.log('Failed in creating imagePacker.'); } // Set encoding parameters if the image packer is successfully created. @@ -252,19 +222,15 @@ let packOpts = { format:["image/jpeg"], // The supported encoding format is jpg. // Encode the image. imagePackerApi.packing(imageSourceApi, packOpts) .then( data => { - console.info('TC_062 finished'); - expect(data !== null).assertTrue(); - done(); + console.log('Succeeded in packing'); }) - + // Release the image packer after the encoding is complete. imagePackerApi.release(); // Obtain the image source information. -imageSourceApi.getImageInfo(imageInfo => { - console.info('TC_045 imageInfo'); - expect(imageInfo !== null).assertTrue(); - done(); +imageSourceApi.getImageInfo((err, imageInfo) => { + console.log('Succeeded in getting imageInfo'); }) // Update incremental data. @@ -283,8 +249,9 @@ public async init(surfaceId: any) { var receiver = image.createImageReceiver(8 * 1024, 8, image.ImageFormat.JPEG, 1); // Obtain the surface ID. - var surfaceId = await receiver.getReceivingSurfaceId(); - + receiver.getReceivingSurfaceId((err, surfaceId) => { + console.info("receiver getReceivingSurfaceId success"); + }); // Register a surface listener, which is triggered after the buffer of the surface is ready. receiver.on('imageArrival', () => { // Obtain the latest buffer of the surface. diff --git a/en/application-dev/media/opensles-capture.md b/en/application-dev/media/opensles-capture.md index 0d0946ca87256f6409a62b81958a2ad784af8161..4e1775e178db20e01f15ee7a9b8f685a5c47b07b 100644 --- a/en/application-dev/media/opensles-capture.md +++ b/en/application-dev/media/opensles-capture.md @@ -1,6 +1,6 @@ # OpenSL ES Audio Recording Development -## When to Use +## Introduction You can use OpenSL ES to develop the audio recording function in OpenHarmony. Currently, only some [OpenSL ES APIs](https://gitee.com/openharmony/third_party_opensles/blob/master/api/1.0.1/OpenSLES.h) are implemented. If an API that has not been implemented is called, **SL_RESULT_FEATURE_UNSUPPORTED** will be returned. diff --git a/en/application-dev/media/opensles-playback.md b/en/application-dev/media/opensles-playback.md index 661bf70ca1551964b05b086d7ec0ab25f46c984d..fe89bc9553da3163e1e18ca43922ff99e13c1307 100644 --- a/en/application-dev/media/opensles-playback.md +++ b/en/application-dev/media/opensles-playback.md @@ -1,6 +1,6 @@ # OpenSL ES Audio Playback Development -## When to Use +## Introduction You can use OpenSL ES to develop the audio playback function in OpenHarmony. Currently, only some [OpenSL ES APIs](https://gitee.com/openharmony/third_party_opensles/blob/master/api/1.0.1/OpenSLES.h) are implemented. If an API that has not been implemented is called, **SL_RESULT_FEATURE_UNSUPPORTED** will be returned. @@ -58,7 +58,7 @@ To use OpenSL ES to develop the audio playback function in OpenHarmony, perform 5. Obtain the **bufferQueueItf** instance of the **SL_IID_OH_BUFFERQUEUE** interface. - ``` + ```c++ SLOHBufferQueueItf bufferQueueItf; (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_OH_BUFFERQUEUE, &bufferQueueItf); ``` diff --git a/en/application-dev/media/video-playback.md b/en/application-dev/media/video-playback.md index 6ee5cf660069294f717c5cac614ed707db9f1a8c..b324f19b3cf0f3621bd74809c4f1a2d0b57d0abd 100644 --- a/en/application-dev/media/video-playback.md +++ b/en/application-dev/media/video-playback.md @@ -1,17 +1,23 @@ # Video Playback Development -## When to Use +## Introduction -You can use video playback APIs to convert video data into visible signals, play the signals using output devices, and manage playback tasks. This document describes development for the following video playback scenarios: full-process, normal playback, video switching, and loop playback. +You can use video playback APIs to convert audio data into audible analog signals and play the signals using output devices. You can also manage playback tasks. For example, you can start, suspend, stop playback, release resources, set the volume, seek to a playback position, set the playback speed, and obtain track information. This document describes development for the following video playback scenarios: full-process, normal playback, video switching, and loop playback. + +## Working Principles + +The following figures show the video playback state transition and the interaction with external modules for video playback. **Figure 1** Video playback state transition ![en-us_image_video_state_machine](figures/en-us_image_video_state_machine.png) -**Figure 2** Layer 0 diagram of video playback +**Figure 2** Interaction with external modules for video playback ![en-us_image_video_player](figures/en-us_image_video_player.png) +**NOTE**: When a third-party application calls a JS interface provided by the JS interface layer, the framework layer invokes the audio component through the media service of the native framework to output the audio data decoded by the software to the audio HDI. The graphics subsystem outputs the image data decoded by the codec HDI at the hardware interface layer to the display HDI. In this way, video playback is implemented. + *Note: Video playback requires hardware capabilities such as display, audio, and codec.* 1. A third-party application obtains a surface ID from the XComponent. diff --git a/en/application-dev/media/video-recorder.md b/en/application-dev/media/video-recorder.md index 62e81cf05c384a7cd1a780c562697be046153d05..bef55899bcb51359a6b6d68ef6d7894d70e435ae 100644 --- a/en/application-dev/media/video-recorder.md +++ b/en/application-dev/media/video-recorder.md @@ -1,17 +1,27 @@ # Video Recording Development -## When to Use +## Introduction -During video recording, audio and video signals are captured, encoded, and saved to files. You can specify parameters such as the encoding format, encapsulation format, and file path for video recording. +You can use video recording APIs to capture audio and video signals, encode them, and save them to files. You can start, suspend, resume, and stop recording, and release resources. You can also specify parameters such as the encoding format, encapsulation format, and file path for video recording. + +## Working Principles + +The following figures show the video recording state transition and the interaction with external modules for video recording. **Figure 1** Video recording state transition ![en-us_image_video_recorder_state_machine](figures/en-us_image_video_recorder_state_machine.png) -**Figure 2** Layer 0 diagram of video recording +**Figure 2** Interaction with external modules for video recording ![en-us_image_video_recorder_zero](figures/en-us_image_video_recorder_zero.png) +**NOTE**: When a third-party camera application or system camera calls a JS interface provided by the JS interface layer, the framework layer uses the media service of the native framework to invoke the audio component. Through the audio HDI, the audio component captures audio data, encodes the audio data through software, and saves the encoded audio data to a file. The graphics subsystem captures image data through the video HDI, encodes the image data through the video codec HDI, and saves the encoded image data to a file. In this way, video recording is implemented. + +## Constraints + +Before developing video recording, configure the permissions **ohos.permission.MICROPHONE** and **ohos.permission.CAMERA** for your application. For details about the configuration, see [Permission Application Guide](../security/accesstoken-guidelines.md). + ## How to Develop For details about the APIs, see [VideoRecorder in the Media API](../reference/apis/js-apis-media.md#videorecorder9). @@ -147,3 +157,4 @@ export class VideoRecorderDemo { } } ``` + diff --git a/en/application-dev/napi/Readme-EN.md b/en/application-dev/napi/Readme-EN.md index 280efd8afa5fa845dab0d607ed94b33e2a75e6d3..b7e5367f1697800cafe3094c5a5a8f2cdb56677e 100644 --- a/en/application-dev/napi/Readme-EN.md +++ b/en/application-dev/napi/Readme-EN.md @@ -4,5 +4,5 @@ - [Drawing Development](drawing-guidelines.md) - [Raw File Development](rawfile-guidelines.md) - [Native Window Development](native-window-guidelines.md) - - +- [Using MindSpore Lite for Model Inference](mindspore-lite-guidelines.md) +- [Connecting the Neural Network Runtime to an AI Inference Framework](neural-network-runtime-guidelines.md) diff --git a/en/application-dev/napi/drawing-guidelines.md b/en/application-dev/napi/drawing-guidelines.md index 7cbf0e3d9e10bb6d8d346e8f6a9910771c523434..1355a27dcf7fb5e54a283ccd5c39a4f1b19de381 100644 --- a/en/application-dev/napi/drawing-guidelines.md +++ b/en/application-dev/napi/drawing-guidelines.md @@ -4,11 +4,11 @@ The Native Drawing module provides APIs for drawing 2D graphics and text. The following scenarios are common for drawing development: * Drawing 2D graphics -* Drawing and painting text +* Drawing text drawing ## Available APIs -| API| Description| +| API| Description| | -------- | -------- | | OH_Drawing_BitmapCreate (void) | Creates a bitmap object.| | OH_Drawing_BitmapBuild (OH_Drawing_Bitmap *, const uint32_t width, const uint32_t height, const OH_Drawing_BitmapFormat *) | Initializes the width and height of a bitmap object and sets the pixel format for the bitmap.| @@ -19,7 +19,7 @@ The Native Drawing module provides APIs for drawing 2D graphics and text. The fo | OH_Drawing_CanvasDrawPath (OH_Drawing_Canvas *, const OH_Drawing_Path *) | Draws a path.| | OH_Drawing_PathCreate (void) | Creates a path object.| | OH_Drawing_PathMoveTo (OH_Drawing_Path *, float x, float y) | Sets the start point of a path.| -| OH_Drawing_PathLineTo (OH_Drawing_Path *, float x, float y) | Draws a line segment from the last point of a path to the target point. | +| OH_Drawing_PathLineTo (OH_Drawing_Path *, float x, float y) | Draws a line segment from the last point of a path to the target point.| | OH_Drawing_PathClose (OH_Drawing_Path *) | Closes a path. A line segment from the start point to the last point of the path is added.| | OH_Drawing_PenCreate (void) | Creates a pen object.| | OH_Drawing_PenSetAntiAlias (OH_Drawing_Pen *, bool) | Checks whether anti-aliasing is enabled for a pen. If anti-aliasing is enabled, edges will be drawn with partial transparency.| @@ -138,7 +138,7 @@ The following steps describe how to use the canvas and brush of the Native Drawi OH_Drawing_BitmapDestory(cBitmap); ``` -## Development Procedure for Text Drawing and Display +## Development Procedure for Text Drawing The following steps describe how to use the text drawing and display feature of the Native Drawing module. 1. **Create a canvas and a bitmap.** @@ -196,7 +196,8 @@ The following steps describe how to use the text drawing and display feature of // Set the maximum width. double maxWidth = 800.0; OH_Drawing_TypographyLayout(typography, maxWidth); - // Set the start position for text display. + // Set the start position for drawing the text on the canvas. double position[2] = {10.0, 15.0}; + // Draw the text on the canvas. OH_Drawing_TypographyPaint(typography, cCanvas, position[0], position[1]); ``` diff --git a/en/application-dev/napi/figures/01.png b/en/application-dev/napi/figures/01.png new file mode 100644 index 0000000000000000000000000000000000000000..5293e5afe5a8637dbef3fd0b32c7bd43d60e4368 Binary files /dev/null and b/en/application-dev/napi/figures/01.png differ diff --git a/en/application-dev/napi/figures/neural_network_runtime.png b/en/application-dev/napi/figures/neural_network_runtime.png new file mode 100644 index 0000000000000000000000000000000000000000..6aafbdab8c2ed989f667acb4068b11b12cba58be Binary files /dev/null and b/en/application-dev/napi/figures/neural_network_runtime.png differ diff --git a/en/application-dev/napi/mindspore-lite-guidelines.md b/en/application-dev/napi/mindspore-lite-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..420d09121f86b7a4612c2e7ad6fe5f29831be80b --- /dev/null +++ b/en/application-dev/napi/mindspore-lite-guidelines.md @@ -0,0 +1,216 @@ +# Using MindSpore Lite for Model Inference + +## When to Use + +MindSpore Lite is an AI engine that provides AI model inference for different hardware devices. It has been used in a wide range of fields, such as image classification, target recognition, facial recognition, and character recognition. + +This document describes the general development process for MindSpore Lite model inference. + +## Basic Concepts + +Before getting started, you need to understand the following basic concepts: + +**Tensor**: a special data structure that is similar to arrays and matrices. It is a basic data structure used in MindSpore Lite network operations. + +**Float16 inference**: a mode in which Float16 is used for inference. Float16, also called half-precision, uses 16 bits to represent a number. + + + +## Available APIs +APIs involved in MindSpore Lite model inference are categorized into context APIs, model APIs, and tensor APIs. +### Context APIs + +| API | Description | +| ------------------ | ----------------- | +|OH_AI_ContextHandle OH_AI_ContextCreate()|Creates a context object.| +|void OH_AI_ContextSetThreadNum(OH_AI_ContextHandle context, int32_t thread_num)|Sets the number of runtime threads.| +| void OH_AI_ContextSetThreadAffinityMode(OH_AI_ContextHandle context, int mode)|Sets the affinity mode for binding runtime threads to CPU cores, which are classified into large, medium, and small cores based on the CPU frequency. You only need to bind the large or medium cores, but not small cores.| +|OH_AI_DeviceInfoHandle OH_AI_DeviceInfoCreate(OH_AI_DeviceType device_type)|Creates a runtime device information object.| +|void OH_AI_ContextDestroy(OH_AI_ContextHandle *context)|Destroys a context object.| +|void OH_AI_DeviceInfoSetEnableFP16(OH_AI_DeviceInfoHandle device_info, bool is_fp16)|Sets whether to enable float16 inference. This function is available only for CPU and GPU devices.| +|void OH_AI_ContextAddDeviceInfo(OH_AI_ContextHandle context, OH_AI_DeviceInfoHandle device_info)|Adds a runtime device information object.| + +### Model APIs + +| API | Description | +| ------------------ | ----------------- | +|OH_AI_ModelHandle OH_AI_ModelCreate()|Creates a model object.| +|OH_AI_Status OH_AI_ModelBuildFromFile(OH_AI_ModelHandle model, const char *model_path,OH_AI_ModelType odel_type, const OH_AI_ContextHandle model_context)|Loads and builds a MindSpore model from a model file.| +|void OH_AI_ModelDestroy(OH_AI_ModelHandle *model)|Destroys a model object.| + +### Tensor APIs + +| API | Description | +| ------------------ | ----------------- | +|OH_AI_TensorHandleArray OH_AI_ModelGetInputs(const OH_AI_ModelHandle model)|Obtains the input tensor array structure of a model.| +|int64_t OH_AI_TensorGetElementNum(const OH_AI_TensorHandle tensor)|Obtains the number of tensor elements.| +|const char *OH_AI_TensorGetName(const OH_AI_TensorHandle tensor)|Obtains the name of a tensor.| +|OH_AI_DataType OH_AI_TensorGetDataType(const OH_AI_TensorHandle tensor)|Obtains the tensor data type.| +|void *OH_AI_TensorGetMutableData(const OH_AI_TensorHandle tensor)|Obtains the pointer to variable tensor data.| + +## How to Develop +The following figure shows the development process for MindSpore Lite model inference. + +**Figure 1** Development process for MindSpore Lite model inference +![how-to-use-mindspore-lite](figures/01.png) + +The development process consists of the following main steps: + +1. Prepare the required model. + + The required model can be downloaded directly or obtained using the model conversion tool. + + - If the downloaded model is in the `.ms` format, you can use it directly for inference. The following uses the **mobilenetv2.ms** model as an example. + - If the downloaded model uses a third-party framework, such as TensorFlow, TensorFlow Lite, Caffe, or ONNX, you can use the [model conversion tool](https://www.mindspore.cn/lite/docs/en/r1.5/use/benchmark_tool.html) to convert it to the `.ms` format. + +2. Create a context, and set parameters such as the number of runtime threads and device type. + + ```c + // Create a context, and set the number of runtime threads to 2 and the thread affinity mode to 1 (big cores first). + OH_AI_ContextHandle context = OH_AI_ContextCreate(); + if (context == NULL) { + printf("OH_AI_ContextCreate failed.\n"); + return OH_AI_STATUS_LITE_ERROR; + } + const int thread_num = 2; + OH_AI_ContextSetThreadNum(context, thread_num); + OH_AI_ContextSetThreadAffinityMode(context, 1); + // Set the device type to CPU, and disable Float16 inference. + OH_AI_DeviceInfoHandle cpu_device_info = OH_AI_DeviceInfoCreate(OH_AI_DEVICETYPE_CPU); + if (cpu_device_info == NULL) { + printf("OH_AI_DeviceInfoCreate failed.\n"); + OH_AI_ContextDestroy(&context); + return OH_AI_STATUS_LITE_ERROR; + } + OH_AI_DeviceInfoSetEnableFP16(cpu_device_info, false); + OH_AI_ContextAddDeviceInfo(context, cpu_device_info); + ``` + +3. Create, load, and build the model. + + Call **OH_AI_ModelBuildFromFile** to load and build the model. + + In this example, the **argv[1]** parameter passed to **OH_AI_ModelBuildFromFile** indicates the specified model file path. + + ```c + // Create a model. + OH_AI_ModelHandle model = OH_AI_ModelCreate(); + if (model == NULL) { + printf("OH_AI_ModelCreate failed.\n"); + OH_AI_ContextDestroy(&context); + return OH_AI_STATUS_LITE_ERROR; + } + + // Load and build the model. The model type is OH_AI_ModelTypeMindIR. + int ret = OH_AI_ModelBuildFromFile(model, argv[1], OH_AI_ModelTypeMindIR, context); + if (ret != OH_AI_STATUS_SUCCESS) { + printf("OH_AI_ModelBuildFromFile failed, ret: %d.\n", ret); + OH_AI_ModelDestroy(&model); + return ret; + } + ``` + +4. Input data. + + Before executing model inference, you need to populate data to the input tensor. In this example, random data is used to populate the model. + + ```c + // Obtain the input tensor. + OH_AI_TensorHandleArray inputs = OH_AI_ModelGetInputs(model); + if (inputs.handle_list == NULL) { + printf("OH_AI_ModelGetInputs failed, ret: %d.\n", ret); + OH_AI_ModelDestroy(&model); + return ret; + } + // Use random data to populate the tensor. + ret = GenerateInputDataWithRandom(inputs); + if (ret != OH_AI_STATUS_SUCCESS) { + printf("GenerateInputDataWithRandom failed, ret: %d.\n", ret); + OH_AI_ModelDestroy(&model); + return ret; + } + ``` + +5. Execute model inference. + + Call **OH_AI_ModelPredict** to perform model inference. + + ```c + // Execute model inference. + OH_AI_TensorHandleArray outputs; + ret = OH_AI_ModelPredict(model, inputs, &outputs, NULL, NULL); + if (ret != OH_AI_STATUS_SUCCESS) { + printf("OH_AI_ModelPredict failed, ret: %d.\n", ret); + OH_AI_ModelDestroy(&model); + return ret; + } + ``` + +6. Obtain the output. + + After model inference is complete, you can obtain the inference result through the output tensor. + + ```c + // Obtain the output tensor and print the information. + for (size_t i = 0; i < outputs.handle_num; ++i) { + OH_AI_TensorHandle tensor = outputs.handle_list[i]; + int64_t element_num = OH_AI_TensorGetElementNum(tensor); + printf("Tensor name: %s, tensor size is %zu ,elements num: %lld.\n", OH_AI_TensorGetName(tensor), + OH_AI_TensorGetDataSize(tensor), element_num); + const float *data = (const float *)OH_AI_TensorGetData(tensor); + printf("output data is:\n"); + const int max_print_num = 50; + for (int j = 0; j < element_num && j <= max_print_num; ++j) { + printf("%f ", data[j]); + } + printf("\n"); + } + ``` + +7. Destroy the model. + + If the MindSpore Lite inference framework is no longer needed, you need to destroy the created model. + + ```c + // Destroy the model. + OH_AI_ModelDestroy(&model); + ``` + +## Verification + +1. Compile **CMakeLists.txt**. + + ```cmake + cmake_minimum_required(VERSION 3.14) + project(Demo) + + add_executable(demo main.c) + + target_link_libraries( + demo + mindspore-lite.huawei + pthread + dl + ) + ``` + - To use ohos-sdk for cross compilation, you need to set the native toolchain path for the CMake tool as follows: `-DCMAKE_TOOLCHAIN_FILE="/xxx/ohos-sdk/linux/native/build/cmake/ohos.toolchain.cmake"`. + + - The toolchain builds a 64-bit application by default. To build a 32-bit application, add the following configuration: `-DOHOS_ARCH="armeabi-v7a"`. + +2. Run the CMake tool. + + - Use hdc_std to connect to the RK3568 development board and put **demo** and **mobilenetv2.ms** to the same directory on the board. + - Run the hdc_std shell command to access the development board, go to the directory where **demo** is located, and run the following command: + + ```shell + ./demo mobilenetv2.ms + ``` + + The inference is successful if the output is similar to the following: + + ```shell + # ./QuickStart ./mobilenetv2.ms + Tensor name: Softmax-65, tensor size is 4004 ,elements num: 1001. + output data is: + 0.000018 0.000012 0.000026 0.000194 0.000156 0.001501 0.000240 0.000825 0.000016 0.000006 0.000007 0.000004 0.000004 0.000004 0.000015 0.000099 0.000011 0.000013 0.000005 0.000023 0.000004 0.000008 0.000003 0.000003 0.000008 0.000014 0.000012 0.000006 0.000019 0.000006 0.000018 0.000024 0.000010 0.000002 0.000028 0.000372 0.000010 0.000017 0.000008 0.000004 0.000007 0.000010 0.000007 0.000012 0.000005 0.000015 0.000007 0.000040 0.000004 0.000085 0.000023 + ``` diff --git a/en/application-dev/napi/napi-guidelines.md b/en/application-dev/napi/napi-guidelines.md index f471f4a6eed7d3eb2c96dab8cae4cb7480a13616..188b4f1336e2c56562f594e42dc26cabf8a8fc55 100644 --- a/en/application-dev/napi/napi-guidelines.md +++ b/en/application-dev/napi/napi-guidelines.md @@ -17,11 +17,11 @@ You can `import` the native .so that contains the JS processing logic. For examp ### .so Naming Rules -Each module has a .so file. For example, if the module name is `hello`, name the .so file **libhello.so**. The `nm_modname` field in `napi_module` must be `hello`, which is the same as the module name. The sample code for importing the .so file is `import hello from 'libhello.so'`. +Each module has a .so file. For example, if the module name is `hello`, name the .so file `libhello.so`. The `nm_modname` field in `napi_module` must be `hello`, which is the same as the module name. The sample code for importing the .so file is `import hello from 'libhello.so'`. ### JS Objects and Threads -The Ark engine prevents NAPIs from being called to operate JS objects in non-JS threads. Otherwise, the application will crash. +The Ark engine prevents NAPIs from being called to operate JS objects in non-JS threads. Otherwise, the application will crash. Observe the following rules: * The NAPIs can be used only in JS threads. * **env** is bound to a thread and cannot be used across threads. The JS object created by a NAPI can be used only in the thread, in which the object is created, that is, the JS object is bound to the **env** of the thread. @@ -640,8 +640,3 @@ export default { } } ``` -## Samples -The following samples are provided for native API development: -- [`NativeAPI`: NativeAPI (eTS) (API8)](https://gitee.com/openharmony/app_samples/tree/master/Native/NativeAPI) -- [First Native C++ Application (eTS) (API9)](https://gitee.com/openharmony/codelabs/tree/master/NativeAPI/NativeTemplateDemo) -- [Native Component (eTS) (API9) ](https://gitee.com/openharmony/codelabs/tree/master/NativeAPI/XComponent) diff --git a/en/application-dev/napi/native-window-guidelines.md b/en/application-dev/napi/native-window-guidelines.md index b92ccc54234c9162dad4b35242dcf9d992e5eeec..a71a261c8d2dc6cee74e79deff99d50814a00007 100644 --- a/en/application-dev/napi/native-window-guidelines.md +++ b/en/application-dev/napi/native-window-guidelines.md @@ -1,107 +1,99 @@ -# NativeWindow Development +# Native Window Development ## When to Use -`NativeWindow` is a local platform window of OpenHarmony. It provides APIs for you to create a native window from `Surface`, create a native window buffer from `SurfaceBuffer`, and request and flush a buffer. +**NativeWindow** is a local platform-based window of OpenHarmony that represents the producer of a graphics queue. It provides APIs for you to create a native window from **Surface**, create a native window buffer from **SurfaceBuffer**, and request and flush a buffer. The following scenarios are common for native window development: -* Drawing content using native C++ code and displaying the content on the screen -* Requesting and flushing a buffer when adapting to EGL `eglswapbuffer` +* Request a graphics buffer by using the NAPI provided by **NativeWindow**, write the produced graphics content to the buffer, and flush the buffer to the graphics queue. +* Request and flush a buffer when adapting to the **eglswapbuffer** interface at the EGL. ## Available APIs | API| Description| | -------- | -------- | -| OH_NativeWindow_CreateNativeWindowFromSurface (void \*pSurface) | Creates a `NativeWindow` instance. A new `NativeWindow` instance is created each time this function is called.| -| OH_NativeWindow_DestroyNativeWindow (struct NativeWindow \*window) | Decreases the reference count of a `NativeWindow` instance by 1 and, when the reference count reaches 0, destroys the instance.| -| OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer (void \*pSurfaceBuffer) | Creates a `NativeWindowBuffer` instance. A new `NativeWindowBuffer` instance is created each time this function is called.| -| OH_NativeWindow_DestroyNativeWindowBuffer (struct NativeWindowBuffer \*buffer) | Decreases the reference count of a `NativeWindowBuffer` instance by 1 and, when the reference count reaches 0, destroys the instance.| -| OH_NativeWindow_NativeWindowRequestBuffer (struct NativeWindow \*window struct NativeWindowBuffer \*\*buffer, int \*fenceFd) | Requests a `NativeWindowBuffer` through a `NativeWindow` instance for content production.| -| OH_NativeWindow_NativeWindowFlushBuffer (struct NativeWindow \*window, struct NativeWindowBuffer \*buffer, int fenceFd, Region region) | Flushes the `NativeWindowBuffer` filled with the content to the buffer queue through a `NativeWindow` instance for content consumption.| -| OH_NativeWindow_NativeWindowCancelBuffer (struct NativeWindow \*window, struct NativeWindowBuffer \*buffer) | Returns the `NativeWindowBuffer` to the buffer queue through a `NativeWindow` instance, without filling in any content. The `NativeWindowBuffer` can be used for another request.| -| OH_NativeWindow_NativeWindowHandleOpt (struct NativeWindow \*window, int code,...) | Sets or obtains the attributes of a native window, including the width, height, and content format.| -| OH_NativeWindow_GetBufferHandleFromNative (struct NativeWindowBuffer \*buffer) | Obtains the pointer to a `BufferHandle` of a `NativeWindowBuffer` instance.| +| OH_NativeWindow_CreateNativeWindowFromSurface (void \*pSurface) | Creates a **NativeWindow** instance. A new **NativeWindow** instance is created each time this function is called.| +| OH_NativeWindow_DestroyNativeWindow (OHNativeWindow \*window) | Decreases the reference count of a **NativeWindow** instance by 1 and, when the reference count reaches 0, destroys the instance.| +| OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer (void \*pSurfaceBuffer) | Creates a **NativeWindowBuffer** instance. A new **NativeWindowBuffer** instance is created each time this function is called.| +| OH_NativeWindow_DestroyNativeWindowBuffer (OHNativeWindowBuffer \*buffer) | Decreases the reference count of a **NativeWindowBuffer** instance by 1 and, when the reference count reaches 0, destroys the instance.| +| OH_NativeWindow_NativeWindowRequestBuffer (OHNativeWindow \*window, OHNativeWindowBuffer \*\*buffer, int \*fenceFd) | Requests a **NativeWindowBuffer** through a **NativeWindow** instance for content production.| +| OH_NativeWindow_NativeWindowFlushBuffer (OHNativeWindow \*window, OHNativeWindowBuffer \*buffer, int fenceFd, Region region) | Flushes the **NativeWindowBuffer** filled with the content to the buffer queue through a **NativeWindow** instance for content consumption.| +| OH_NativeWindow_NativeWindowAbortBuffer (OHNativeWindow \*window, OHNativeWindowBuffer \*buffer) | Returns the **NativeWindowBuffer** to the buffer queue through a **NativeWindow** instance, without filling in any content. The **NativeWindowBuffer** can be used for another request.| +| OH_NativeWindow_NativeWindowHandleOpt (OHNativeWindow \*window, int code,...) | Sets or obtains the attributes of a native window, including the width, height, and content format.| +| OH_NativeWindow_GetBufferHandleFromNative (OHNativeWindowBuffer \*buffer) | Obtains the pointer to a **BufferHandle** of a **NativeWindowBuffer** instance.| | OH_NativeWindow_NativeObjectReference (void \*obj) | Adds the reference count of a native object.| | OH_NativeWindow_NativeObjectUnreference (void \*obj) | Decreases the reference count of a native object and, when the reference count reaches 0, destroys this object.| | OH_NativeWindow_GetNativeObjectMagic (void \*obj) | Obtains the magic ID of a native object.| - +| OH_NativeWindow_NativeWindowSetScalingMode (OHNativeWindow \*window, uint32_t sequence, OHScalingMode scalingMode) | Sets the scaling mode of the native window.| +| OH_NativeWindow_NativeWindowSetMetaData(OHNativeWindow \*window, uint32_t sequence, int32_t size, const OHHDRMetaData \*metaData) | Sets the HDR static metadata of the native window.| +| OH_NativeWindow_NativeWindowSetMetaDataSet(OHNativeWindow \*window, uint32_t sequence, OHHDRMetadataKey key, int32_t size, const uint8_t \*metaData) | Sets the HDR static metadata set of the native window.| +| OH_NativeWindow_NativeWindowSetTunnelHandle(OHNativeWindow \*window, const OHExtDataHandle \*handle) | Sets the tunnel handle to the native window.| ## How to Develop -The following steps describe how to use `OH_NativeXComponent` in OpenHarmony to draw content using native C++ code and display the content on the screen. - -1. Define an `XComponent` of the `texture` type in `index.ets` for content display. - ```js - XComponent({ id: 'xcomponentId', type: 'texture', libraryname: 'nativerender'}) - .borderColor(Color.Red) - .borderWidth(5) - .onLoad(() => {}) - .onDestroy(() => {}) - ``` - -2. Obtain an `OH_NativeXComponent` instance (named `nativeXComponent` in this example) by calling `napi_get_named_property`, and obtain a `NativeWindow` instance by registering the callback of the `OH_NativeXComponent` instance. +The following describes how to use the NAPI provided by **NativeWindow** to request a graphics buffer, write the produced graphics content to the buffer, and flush the buffer to the graphics queue. +1. Obtain a **NativeWindow** instance. For example, use **Surface** to create a **NativeWindow** instance. ```c++ - // Define a NAPI instance. - napi_value exportInstance = nullptr; - // Define an OH_NativeXComponent instance. - OH_NativeXComponent *nativeXComponent = nullptr; - // Use the OH_NATIVE_XCOMPONENT_OBJ export instance. - napi_getname_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance); - // Convert the NAPI instance to the OH_NativeXComponent instance. - napi_unwarp(env, exportInstance, reinterpret_cast(&nativeXComponent)); + sptr cSurface = Surface::CreateSurfaceAsConsumer(); + sptr listener = new BufferConsumerListenerTest(); + cSurface->RegisterConsumerListener(listener); + sptr producer = cSurface->GetProducer(); + sptr pSurface = Surface::CreateSurfaceAsProducer(producer); + OHNativeWindow* nativeWindow = OH_NativeWindow_CreateNativeWindow(&pSurface); ``` -3. Define the callback `OnSurfaceCreated`. During the creation of a `Surface`, the callback is used to initialize the rendering environment, for example, the `Skia` rendering environment, and write the content to be displayed to `NativeWindow`. - +2. Set the attributes of a native window buffer by using **OH_NativeWindow_NativeWindowHandleOpt**. ```c++ - void OnSurfaceCreatedCB(NativeXComponent* component, void* window) { - // Obtain the width and height of the native window. - uint64_t width_ = 0, height_ = 0; - OH_NativeXComponent_GetXComponentSize(nativeXComponent, window, &width_, &height_); - // Convert void* into a NativeWindow instance. NativeWindow is defined in native_window/external_window.h. - NativeWindow* nativeWindow_ = (NativeWindow*)(window); - - // Set or obtain the NativeWindow attributes by calling OH_NativeWindow_NativeWindowHandleOpt. - // 1. Use SET_USAGE to set the usage attribute of the native window, for example, to HBM_USE_CPU_READ. - OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, SET_USAGE, HBM_USE_CPU_READ | HBM_USE_CPU_WRITE |HBM_USE_MEM_DMA); - // 2. Use SET_BUFFER_GEOMETRY to set the width and height attributes of the native window. - OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, SET_BUFFER_GEOMETRY, width_, height_); - // 3. Use SET_FORMAT to set the format attribute of the native window, for example, to PIXEL_FMT_RGBA_8888. - OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, SET_FORMAT, PIXEL_FMT_RGBA_8888); - // 4. Use SET_STRIDE to set the stride attribute of the native window. - OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, SET_STRIDE, 0x8); - - // Obtain the NativeWindowBuffer instance by calling OH_NativeWindow_NativeWindowRequestBuffer. - struct NativeWindowBuffer* buffer = nullptr; - int fenceFd; - OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer, &fenceFd); - - // Obtain the buffer handle by calling OH_NativeWindow_GetNativeBufferHandleFromNative. - BufferHandle* bufferHandle = OH_NativeWindow_GetNativeBufferHandleFromNative(buffer); + // Set the read and write scenarios of the native window buffer. + int code = SET_USAGE; + int32_t usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA; + int32_t ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, usage); + // Set the width and height of the native window buffer. + code = SET_BUFFER_GEOMETRY; + int32_t width = 0x100; + int32_t height = 0x100; + ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, width, height); + // Set the step of the native window buffer. + code = SET_STRIDE; + int32_t stride = 0x8; + ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, stride); + // Set the format of the native window buffer. + code = SET_FORMAT; + int32_t format = PIXEL_FMT_RGBA_8888; + ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, format); + ``` - // Create a Skia bitmap using BufferHandle. - SkBitmap bitmap; - SkImageInfo imageInfo = ... - bitmap.setInfo(imageInfo, bufferHandle->stride); - bitmap.setPixels(bufferHandle->virAddr); - // Create Skia Canvas and write the content to the native window. - ... +3. Request a native window buffer from the graphics queue. + ```c++ + struct NativeWindowBuffer* buffer = nullptr; + int fenceFd; + // Obtain the NativeWindowBuffer instance by calling OH_NativeWindow_NativeWindowRequestBuffer. + OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer, &fenceFd); + // Obtain the buffer handle by calling OH_NativeWindow_GetNativeBufferHandleFromNative. + BufferHandle* bufferHandle = OH_NativeWindow_GetNativeBufferHandleFromNative(buffer); + ``` - // After the write operation is complete, flush the buffer by using OH_NativeWindow_NativeWindowFlushBuffer so that the data is displayed on the screen. - Region region{nullptr, 0}; - OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer, fenceFd, region) +4. Write the produced content to the native window buffer. + ```c++ + auto image = static_cast(buffer->sfbuffer->GetVirAddr()); + static uint32_t value = 0x00; + value++; + + uint32_t *pixel = static_cast(image); + for (uint32_t x = 0; x < width; x++) { + for (uint32_t y = 0; y < height; y++) { + *pixel++ = value; + } } ``` -4. Register the callback `OnSurfaceCreated` by using `OH_NativeXComponent_RegisterCallback`. +5. Flush the native window buffer to the graphics queue. ```c++ - OH_NativeXComponent_Callback &callback_; - callback_->OnSurfaceCreated = OnSurfaceCreatedCB; - callback_->OnSurfaceChanged = OnSurfaceChangedCB; - callback_->OnSurfaceDestoryed = OnSurfaceDestoryedCB; - callback_->DispatchTouchEvent = DispatchTouchEventCB; - OH_NativeXComponent_RegisterCallback(nativeXComponent, callback_) + // Set the refresh region. If Rect in Region is a null pointer or rectNumber is 0, all contents in the native window buffer are changed. + Region region{nullptr, 0}; + // Flush the buffer to the consumer through OH_NativeWindow_NativeWindowFlushBuffer, for example, by displaying it on the screen. + OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer, fenceFd, region); ``` diff --git a/en/application-dev/napi/neural-network-runtime-guidelines.md b/en/application-dev/napi/neural-network-runtime-guidelines.md new file mode 100644 index 0000000000000000000000000000000000000000..9ae694fc12449634a75fae260050188b68e97804 --- /dev/null +++ b/en/application-dev/napi/neural-network-runtime-guidelines.md @@ -0,0 +1,491 @@ +# Connecting the Neural Network Runtime to an AI Inference Framework + +## When to Use + +As a bridge between the AI inference engine and acceleration chip, the Neural Network Runtime provides simplified Native APIs for the AI inference engine to perform end-to-end inference through the acceleration chip. + +This document uses the `Add` single-operator model shown in Figure 1 as an example to describe the development process of Neural Network Runtime. The `Add` operator involves two inputs, one parameter, and one output. Wherein, the `activation` parameter is used to specify the type of the activation function in the `Add` operator. + +**Figure 1** Add single-operator model +!["Add single-operator model"](figures/neural_network_runtime.png) + +## Preparing the Environment + +### Environment Requirements + +The environment requirements for the Neural Network Runtime are as follows: + +- System version: OpenHarmony master branch. +- Development environment: Ubuntu 18.04 or later. +- Access device: a standard device running OpenHarmony. The built-in hardware accelerator driver has been connected to the Neural Network Runtime through an HDI API. + +The Neural Network Runtime is opened to external systems through OpenHarmony Native APIs. Therefore, you need to use the Native development suite of the OpenHarmony to compile Neural Network Runtime applications. You can download the **ohos-sdk** package of the corresponding version from [Daily Build](http://ci.openharmony.cn/dailys/dailybuilds) in the OpenHarmony community and then decompress the package to obtain the Native development suite of the corresponding platform. Take Linux as an example. The package of the Native development suite is named `native-linux-{version number}.zip`. + +### Environment Setup + +1. Start the Ubuntu server. +2. Copy the downloaded package of the Native development suite to the root directory of the current user. +3. Decompress the package of the Native development suite. +```shell +unzip native-linux-{version number}.zip +``` + +The directory structure after decompression is as follows. The content in the directory may vary depending on version iteration. Use the Native APIs of the latest version. +```text +native/ +─ ─ build // Cross-compilation toolchain +─ ─ build-tools // Compilation and build tools +├── docs +├── llvm +├── nativeapi_syscap_config.json +├── ndk_system_capability.json +├── NOTICE.txt +├── oh-uni-package.json +── sysroot // Native API header files and libraries +``` +## Available APIs + +This section describes the common APIs used in the development process of the Neural Network Runtime. + +### Structure + +| Name| Description| +| --------- | ---- | +| typedef struct OH_NNModel OH_NNModel | Model handle of the Neural Network Runtime. It is used to construct a model.| +| typedef struct OH_NNCompilation OH_NNCompilation | Compiler handle of the Neural Network Runtime. It is used to compile an AI model.| +| typedef struct OH_NNExecutor OH_NNExecutor | Executor handle of the Neural Network Runtime. It is used to perform inference computing on a specified device.| + +### Model Construction APIs + +| Name| Description| +| ------- | --- | +| OH_NNModel_Construct() | Creates a model instance of the OH_NNModel type.| +| OH_NN_ReturnCode OH_NNModel_AddTensor(OH_NNModel *model, const OH_NN_Tensor *tensor) | Adds a tensor to a model instance.| +| OH_NN_ReturnCode OH_NNModel_SetTensorData(OH_NNModel *model, uint32_t index, const void *dataBuffer, size_t length) | Sets the tensor value.| +| OH_NN_ReturnCode OH_NNModel_AddOperation(OH_NNModel *model, OH_NN_OperationType op, const OH_NN_UInt32Array *paramIndices, const OH_NN_UInt32Array *inputIndices, const OH_NN_UInt32Array *outputIndices) | Adds an operator to a model instance.| +| OH_NN_ReturnCode OH_NNModel_SpecifyInputsAndOutputs(OH_NNModel *model, const OH_NN_UInt32Array *inputIndices, const OH_NN_UInt32Array *outputIndices) | Specifies the model input and output.| +| OH_NN_ReturnCode OH_NNModel_Finish(OH_NNModel *model) | Completes model composition.| +| void OH_NNModel_Destroy(OH_NNModel **model) | Destroys a model instance.| + +### Model Compilation APIs + +| Name| Description| +| ------- | --- | +| OH_NNCompilation *OH_NNCompilation_Construct(const OH_NNModel *model) | Creates a compilation instance of the OH_NNCompilation type.| +| OH_NN_ReturnCode OH_NNCompilation_SetDevice(OH_NNCompilation *compilation, size_t deviceID) | Specifies the device for model compilation and computing.| +| OH_NN_ReturnCode OH_NNCompilation_SetCache(OH_NNCompilation *compilation, const char *cachePath, uint32_t version) | Sets the cache directory and version of the compiled model.| +| OH_NN_ReturnCode OH_NNCompilation_Build(OH_NNCompilation *compilation) | Performs model compilation.| +| void OH_NNCompilation_Destroy(OH_NNCompilation **compilation) | Destroys the OH_NNCompilation instance.| + +### Inference Execution APIs + +| Name| Description| +| ------- | --- | +| OH_NNExecutor *OH_NNExecutor_Construct(OH_NNCompilation *compilation) | Creates an executor instance of the OH_NNExecutor type.| +| OH_NN_ReturnCode OH_NNExecutor_SetInput(OH_NNExecutor *executor, uint32_t inputIndex, const OH_NN_Tensor *tensor, const void *dataBuffer, size_t length) | Sets the single input data for a model.| +| OH_NN_ReturnCode OH_NNExecutor_SetOutput(OH_NNExecutor *executor, uint32_t outputIndex, void *dataBuffer, size_t length) | Sets the buffer for a single output of a model.| +| OH_NN_ReturnCode OH_NNExecutor_Run(OH_NNExecutor *executor) | Executes model inference.| +| void OH_NNExecutor_Destroy(OH_NNExecutor **executor) | Destroys the OH_NNExecutor instance to release the memory occupied by the instance.| + +### Device Management APIs + +| Name| Description| +| ------- | --- | +| OH_NN_ReturnCode OH_NNDevice_GetAllDevicesID(const size_t **allDevicesID, uint32_t *deviceCount) | Obtains the ID of the device connected to the Neural Network Runtime.| + + +## How to Develop + +The development process of the Neural Network Runtime consists of three phases: model construction, model compilation, and inference execution. The following uses the `Add` single-operator model as an example to describe how to call Neural Network Runtime APIs during application development. + +1. Create an application sample file. + + Create the source file of the Neural Network Runtime application sample. Run the following commands in the project directory to create the `nnrt_example/` directory and create the `nnrt_example.cpp` source file in the directory: + + ```shell + mkdir ~/nnrt_example && cd ~/nnrt_example + touch nnrt_example.cpp + ``` + +2. Import the Neural Network Runtime module. + + Add the following code at the beginning of the `nnrt_example.cpp` file to import the Neural Network Runtime module: + + ```cpp + #include + #include + #include + + #include "neural_network_runtime/neural_network_runtime.h" + + // Constant, used to specify the byte length of the input and output data. + const size_t DATA_LENGTH = 4 * 12; + ``` + +3. Construct a model. + + Use Neural Network Runtime APIs to construct an `Add` single-operator sample model. + + ```cpp + OH_NN_ReturnCode BuildModel(OH_NNModel** pModel) + { + // Create a model instance and construct a model. + OH_NNModel* model = OH_NNModel_Construct(); + if (model == nullptr) { + std::cout << "Create model failed." << std::endl; + return OH_NN_MEMORY_ERROR; + } + + // Add the first input tensor of the float32 type for the Add operator. The tensor shape is [1, 2, 2, 3]. + int32_t inputDims[4] = {1, 2, 2, 3}; + OH_NN_Tensor input1 = {OH_NN_FLOAT32, 4, inputDims, nullptr, OH_NN_TENSOR}; + OH_NN_ReturnCode ret = OH_NNModel_AddTensor(model, &input1); + if (ret != OH_NN_SUCCESS) { + std::cout << "BuildModel failed, add Tensor of first input failed." << std::endl; + return ret; + } + + // Add the second input tensor of the float32 type for the Add operator. The tensor shape is [1, 2, 2, 3]. + OH_NN_Tensor input2 = {OH_NN_FLOAT32, 4, inputDims, nullptr, OH_NN_TENSOR}; + ret = OH_NNModel_AddTensor(model, &input2); + if (ret != OH_NN_SUCCESS) { + std::cout << "BuildModel failed, add Tensor of second input failed." << std::endl; + return ret; + } + + // Add the Tensor parameter of the Add operator. This parameter is used to specify the type of the activation function. The data type of the Tensor parameter is int8. + int32_t activationDims = 1; + int8_t activationValue = OH_NN_FUSED_NONE; + OH_NN_Tensor activation = {OH_NN_INT8, 1, &activationDims, nullptr, OH_NN_ADD_ACTIVATIONTYPE}; + ret = OH_NNModel_AddTensor(model, &activation); + if (ret != OH_NN_SUCCESS) { + std::cout << "BuildModel failed, add Tensor of activation failed." << std::endl; + return ret; + } + + // Set the type of the activation function to OH_NN_FUSED_NONE, indicating that no activation function is added to the operator. + ret = OH_NNModel_SetTensorData(model, 2, &activationValue, sizeof(int8_t)); + if (ret != OH_NN_SUCCESS) { + std::cout << "BuildModel failed, set value of activation failed." << std::endl; + return ret; + } + + // Set the output of the Add operator. The data type is float32 and the tensor shape is [1, 2, 2, 3]. + OH_NN_Tensor output = {OH_NN_FLOAT32, 4, inputDims, nullptr, OH_NN_TENSOR}; + ret = OH_NNModel_AddTensor(model, &output); + if (ret != OH_NN_SUCCESS) { + std::cout << "BuildModel failed, add Tensor of output failed." << std::endl; + return ret; + } + + // Specify the input, parameter, and output indexes of the Add operator. + uint32_t inputIndicesValues[2] = {0, 1}; + uint32_t paramIndicesValues = 2; + uint32_t outputIndicesValues = 3; + OH_NN_UInt32Array paramIndices = {¶mIndicesValues, 1}; + OH_NN_UInt32Array inputIndices = {inputIndicesValues, 2}; + OH_NN_UInt32Array outputIndices = {&outputIndicesValues, 1}; + + // Add the Add operator to the model instance. + ret = OH_NNModel_AddOperation(model, OH_NN_OPS_ADD, ¶mIndices, &inputIndices, &outputIndices); + if (ret != OH_NN_SUCCESS) { + std::cout << "BuildModel failed, add operation failed." << std::endl; + return ret; + } + + // Set the input and output indexes of the model instance. + ret = OH_NNModel_SpecifyInputsAndOutputs(model, &inputIndices, &outputIndices); + if (ret != OH_NN_SUCCESS) { + std::cout << "BuildModel failed, specify inputs and outputs failed." << std::endl; + return ret; + } + + // Complete the model instance construction. + ret = OH_NNModel_Finish(model); + if (ret != OH_NN_SUCCESS) { + std::cout << "BuildModel failed, error happened when finishing model construction." << std::endl; + return ret; + } + + *pModel = model; + return OH_NN_SUCCESS; + } + ``` + +4. Query the acceleration chip connected to the Neural Network Runtime. + + The Neural Network Runtime can connect to multiple acceleration chips through HDI APIs. Before model compilation, you need to query the acceleration chips connected to the Neural Network Runtime on the current device. Each acceleration chip has a unique ID. In the compilation phase, you need to specify the chip for model compilation based on the device ID. + ```cpp + void GetAvailableDevices(std::vector& availableDevice) + { + availableDevice.clear(); + + // Obtain the available hardware ID. + const size_t* devices = nullptr; + uint32_t deviceCount = 0; + OH_NN_ReturnCode ret = OH_NNDevice_GetAllDevicesID(&devices, &deviceCount); + if (ret != OH_NN_SUCCESS) { + std::cout << "GetAllDevicesID failed, get no available device." << std::endl; + return; + } + + for (uint32_t i = 0; i < deviceCount; i++) { + availableDevice.emplace_back(devices[i]); + } + } + ``` + +5. Compile a model on the specified device. + + The Neural Network Runtime uses abstract model expressions to describe the topology structure of an AI model. Before inference execution on an acceleration chip, the compilation module provided by Neural Network Runtime needs to deliver the abstract model expression to the chip driver layer and convert the abstract model expression into a format that supports inference and computing. + ```cpp + OH_NN_ReturnCode CreateCompilation(OH_NNModel* model, const std::vector& availableDevice, OH_NNCompilation** pCompilation) + { + // Create a compilation instance to pass the model to the underlying hardware for compilation. + OH_NNCompilation* compilation = OH_NNCompilation_Construct(model); + if (compilation == nullptr) { + std::cout << "CreateCompilation failed, error happended when creating compilation." << std::endl; + return OH_NN_MEMORY_ERROR; + } + + // Set compilation options, such as the compilation hardware, cache path, performance mode, computing priority, and whether to enable float16 low-precision computing. + + // Choose to perform model compilation on the first device. + OH_NN_ReturnCode ret = OH_NNCompilation_SetDevice(compilation, availableDevice[0]); + if (ret != OH_NN_SUCCESS) { + std::cout << "CreateCompilation failed, error happened when setting device." << std::endl; + return ret; + } + + // Have the model compilation result cached in the /data/local/tmp directory, with the version number set to 1. + ret = OH_NNCompilation_SetCache(compilation, "/data/local/tmp", 1); + if (ret != OH_NN_SUCCESS) { + std::cout << "CreateCompilation failed, error happened when setting cache path." << std::endl; + return ret; + } + + // Start model compilation. + ret = OH_NNCompilation_Build(compilation); + if (ret != OH_NN_SUCCESS) { + std::cout << "CreateCompilation failed, error happened when building compilation." << std::endl; + return ret; + } + + *pCompilation = compilation; + return OH_NN_SUCCESS; + } + ``` + +6. Create an executor. + + After the model compilation is complete, you need to call the execution module of the Neural Network Runtime to create an inference executor. In the execution phase, operations such as setting the model input, obtaining the model output, and triggering inference computing are performed through the executor. + ```cpp + OH_NNExecutor* CreateExecutor(OH_NNCompilation* compilation) + { + // Create an executor instance. + OH_NNExecutor* executor = OH_NNExecutor_Construct(compilation); + return executor; + } + ``` + +7. Perform inference computing and print the computing result. + + The input data required for inference computing is passed to the executor through the API provided by the execution module. This way, the executor is triggered to perform inference computing once to obtain the inference computing result. + ```cpp + OH_NN_ReturnCode Run(OH_NNExecutor* executor) + { + // Construct sample data. + float input1[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + float input2[12] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}; + + int32_t inputDims[4] = {1, 2, 2, 3}; + OH_NN_Tensor inputTensor1 = {OH_NN_FLOAT32, 4, inputDims, nullptr, OH_NN_TENSOR}; + OH_NN_Tensor inputTensor2 = {OH_NN_FLOAT32, 4, inputDims, nullptr, OH_NN_TENSOR}; + + // Set the execution input. + + // Set the first input for execution. The input data is specified by input1. + OH_NN_ReturnCode ret = OH_NNExecutor_SetInput(executor, 0, &inputTensor1, input1, DATA_LENGTH); + if (ret != OH_NN_SUCCESS) { + std::cout << "Run failed, error happened when setting first input." << std::endl; + return ret; + } + + // Set the second input for execution. The input data is specified by input2. + ret = OH_NNExecutor_SetInput(executor, 1, &inputTensor2, input2, DATA_LENGTH); + if (ret != OH_NN_SUCCESS) { + std::cout << "Run failed, error happened when setting second input." << std::endl; + return ret; + } + + // Set the output data cache. After the OH_NNExecutor_Run instance performs inference computing, the output result is stored in the output. + float output[12]; + ret = OH_NNExecutor_SetOutput(executor, 0, output, DATA_LENGTH); + if (ret != OH_NN_SUCCESS) { + std::cout << "Run failed, error happened when setting output buffer." << std::endl; + return ret; + } + + // Perform inference computing. + ret = OH_NNExecutor_Run(executor); + if (ret != OH_NN_SUCCESS) { + std::cout << "Run failed, error doing execution." << std::endl; + return ret; + } + + // Print the output result. + for (uint32_t i = 0; i < 12; i++) { + std::cout << "Output index: " << i << ", value is: " << output[i] << "." << std::endl; + } + + return OH_NN_SUCCESS; + } + ``` + +8. Build an end-to-end process from model construction to model compilation and execution. + + Steps 3 to 7 implement the model construction, compilation, and execution processes and encapsulates them into four functions to facilitate modular development. The following sample code shows how to concatenate the four functions into a complete Neural Network Runtime the development process. + ```cpp + int main() + { + OH_NNModel* model = nullptr; + OH_NNCompilation* compilation = nullptr; + OH_NNExecutor* executor = nullptr; + std::vector availableDevices; + + // Perform model construction. + OH_NN_ReturnCode ret = BuildModel(&model); + if (ret != OH_NN_SUCCESS) { + std::cout << "BuildModel failed." << std::endl; + OH_NNModel_Destroy(&model); + return -1; + } + + // Obtain the available devices. + GetAvailableDevices(availableDevices); + if (availableDevices.empty()) { + std::cout << "No available device." << std::endl; + OH_NNModel_Destroy(&model); + return -1; + } + + // Perform model compilation. + ret = CreateCompilation(model, availableDevices, &compilation); + if (ret != OH_NN_SUCCESS) { + std::cout << "CreateCompilation failed." << std::endl; + OH_NNModel_Destroy(&model); + OH_NNCompilation_Destroy(&compilation); + return -1; + } + + // Create an inference executor for the model. + executor = CreateExecutor(compilation); + if (executor == nullptr) { + std::cout << "CreateExecutor failed, no executor is created." << std::endl; + OH_NNModel_Destroy(&model); + OH_NNCompilation_Destroy(&compilation); + return -1; + } + + // Use the created executor to perform single-step inference computing. + ret = Run(executor); + if (ret != OH_NN_SUCCESS) { + std::cout << "Run failed." << std::endl; + OH_NNModel_Destroy(&model); + OH_NNCompilation_Destroy(&compilation); + OH_NNExecutor_Destroy(&executor); + return -1; + } + + // Destroy the model to release occupied resources. + OH_NNModel_Destroy(&model); + OH_NNCompilation_Destroy(&compilation); + OH_NNExecutor_Destroy(&executor); + + return 0; + } + ``` + +## Verification + +1. Prepare the compilation configuration file of the application sample. + + Create a `CMakeLists.txt` file, and add compilation configurations to the application sample file `nnrt_example.cpp`. The following is a simple example of the `CMakeLists.txt` file: + ```text + cmake_minimum_required(VERSION 3.16) + project(nnrt_example C CXX) + + add_executable(nnrt_example + ./nnrt_example.cpp + ) + + target_link_libraries(nnrt_example + neural_network_runtime.z + ) + ``` + +2. Compile the application sample. + + Create the **build/** directory in the current directory, and compile `nnrt\_example.cpp` in the **build/** directory to obtain the binary file `nnrt\_example`: + ```shell + mkdir build && cd build + cmake -DCMAKE_TOOLCHAIN_FILE={Path of the cross-compilation tool chain }/build/cmake/ohos.toolchain.cmake -DOHOS_ARCH=arm64-v8a -DOHOS_PLATFORM=OHOS -DOHOS_STL=c++_static .. + make + ``` + +3. Push the application sample to the device for execution. + ```shell + # Push the `nnrt_example` obtained through compilation to the device, and execute it. + hdc_std file send ./nnrt_example /data/local/tmp/. + + # Grant required permissions to the executable file of the test case. + hdc_std shell "chmod +x /data/local/tmp/nnrt_example" + + # Execute the test case. + hdc_std shell "/data/local/tmp/nnrt_example" + ``` + + If the execution is normal, information similar to the following is displayed: + ```text + Output index: 0, value is: 11.000000. + Output index: 1, value is: 13.000000. + Output index: 2, value is: 15.000000. + Output index: 3, value is: 17.000000. + Output index: 4, value is: 19.000000. + Output index: 5, value is: 21.000000. + Output index: 6, value is: 23.000000. + Output index: 7, value is: 25.000000. + Output index: 8, value is: 27.000000. + Output index: 9, value is: 29.000000. + Output index: 10, value is: 31.000000. + Output index: 11, value is: 33.000000. + ``` + +4. (Optional) Check the model cache. + + If the HDI service connected to the Neural Network Runtime supports the model cache function, you can find the generated cache file in the `/data/local/tmp` directory after the `nnrt_example` is executed successfully. + + > **NOTE** + > + > The IR graphs of the model need to be passed to the hardware driver layer, so that the HDI service compiles the IR graphs into a computing graph dedicated to hardware. The compilation process is time-consuming. The Neural Network Runtime supports the computing graph cache feature. It can cache the computing graphs compiled by the HDI service to the device storage. If the same model is compiled on the same acceleration chip next time, you can specify the cache path so that the Neural Network Runtime can directly load the computing graphs in the cache file, reducing the compilation time. + + Check the cached files in the cache directory. + ```shell + ls /data/local/tmp + ``` + + The command output is as follows: + ```text + # 0.nncache cache_info.nncache + ``` + + If the cache is no longer used, manually delete the cache files. + ```shell + rm /data/local/tmp/*nncache + ``` + +## Samples + +The following sample is provided to help you understand how to connect a third-party AI inference framework to the Neural Network Runtime: +- [Development Guide for Connecting TensorFlow Lite to NNRt Delegate](https://gitee.com/openharmony/neural_network_runtime/tree/master/example/deep_learning_framework) + diff --git a/en/application-dev/notification/background-agent-scheduled-reminder-guide.md b/en/application-dev/notification/background-agent-scheduled-reminder-guide.md index 1894942945c53a4d36bc2f9c892de28359faa9ff..71ffeb0b07acfb088988163a68f72882d267f49b 100644 --- a/en/application-dev/notification/background-agent-scheduled-reminder-guide.md +++ b/en/application-dev/notification/background-agent-scheduled-reminder-guide.md @@ -37,9 +37,7 @@ For details about the APIs, see [reminderAgent](../reference/apis/js-apis-remind import reminderAgent from '@ohos.reminderAgent'; import notification from '@ohos.notification'; export default { - // For a JS project: - // timer: { - // For an eTS project: + // ArkTS project: let timer : reminderAgent.ReminderRequestTimer = { reminderType: reminderAgent.ReminderType.REMINDER_TYPE_TIMER, triggerTimeInSeconds: 10, @@ -69,9 +67,7 @@ For details about the APIs, see [reminderAgent](../reference/apis/js-apis-remind Sample code for defining a reminder agent for a calendar event: ```js - // For a JS project: - // calendar: { - // For an eTS project: + // ArkTS project: let calendar : reminderAgent.ReminderRequestCalendar = { reminderType: reminderAgent.ReminderType.REMINDER_TYPE_CALENDAR, dateTime: { @@ -117,9 +113,7 @@ For details about the APIs, see [reminderAgent](../reference/apis/js-apis-remind Sample code for defining a reminder agent for an alarm: ```js - // For a JS project: - // alarm: { - // For an eTS project: + // ArkTS project: let alarm : reminderAgent.ReminderRequestAlarm = { reminderType: reminderAgent.ReminderType.REMINDER_TYPE_ALARM, hour: 11, @@ -171,4 +165,3 @@ For details about the APIs, see [reminderAgent](../reference/apis/js-apis-remind ``` - diff --git a/en/application-dev/notification/common-event.md b/en/application-dev/notification/common-event.md index d5a6d7bdfbc6dcdd5b94d36e155d4650fc70630c..dfb611ea572b80486756faaa4b004513cd6858a7 100644 --- a/en/application-dev/notification/common-event.md +++ b/en/application-dev/notification/common-event.md @@ -13,14 +13,14 @@ Each application can subscribe to common events as required. After your applicat ## Common Event Subscription Development ### When to Use -You can create a subscriber object to subscribe to a common event to obtain the parameters passed in the event. Certain system common events require specific permissions to subscribe to. For details, see [Required Permissions](../reference/apis/js-apis-commonEvent.md). +You can create a subscriber object to subscribe to a common event to obtain the parameters passed in the event. Certain system common events require specific permissions to subscribe to. For details, see [Required Permissions](../reference/apis/js-apis-commonEvent.md#support). ### Available APIs | API | Description| | ---------------------------------------------------------------------------------------------- | ----------- | -| commonEvent.createSubscriber(subscribeInfo: CommonEventSubscribeInfo, callback: AsyncCallback) | Creates a subscriber. This API uses a callback to return the result.| -| commonEvent.createSubscriber(subscribeInfo: CommonEventSubscribeInfo) | Creates a subscriber. This API uses a promise to return the result. | -| commonEvent.subscribe(subscriber: CommonEventSubscriber, callback: AsyncCallback) | Subscribes to common events.| +| createSubscriber(subscribeInfo: CommonEventSubscribeInfo, callback: AsyncCallback) | Creates a subscriber. This API uses a callback to return the result.| +| createSubscriber(subscribeInfo: CommonEventSubscribeInfo) | Creates a subscriber. This API uses a promise to return the result. | +| subscribe(subscriber: CommonEventSubscriber, callback: AsyncCallback) | Subscribes to common events.| ### How to Develop 1. Import the **commonEvent** module. @@ -32,7 +32,8 @@ import commonEvent from '@ohos.commonEvent'; 2. Create a **subscribeInfo** object. For details about the data types and parameters of the object, see [CommonEventSubscribeInfo](../reference/apis/js-apis-commonEvent.md#commoneventsubscribeinfo). ```js -private subscriber = null // Used to save the created subscriber object for subsequent subscription and unsubscription. +// Used to save the created subscriber object for subsequent subscription and unsubscription. +private subscriber = null // Subscriber information var subscribeInfo = { @@ -82,8 +83,8 @@ You can use the **publish** APIs to publish a custom common event, which can car ### Available APIs | API | Description| | ---------------------------------- | ------ | -| commonEvent.publish(event: string, callback: AsyncCallback) | Publishes a common event.| -| commonEvent.publish(event: string, options: CommonEventPublishData, callback: AsyncCallback) | Publishes a common event with given attributes.| +| publish(event: string, callback: AsyncCallback) | Publishes a common event.| +| publish(event: string, options: CommonEventPublishData, callback: AsyncCallback) | Publishes a common event with given attributes.| ### How to Develop #### Development for Publishing a Common Event @@ -119,7 +120,7 @@ import commonEvent from '@ohos.commonEvent' // Attributes of a common event. var options = { code: 1, // Result code of the common event - data: "initial data",// Result data of the common event + data: "initial data";// Result data of the common event } ``` @@ -144,7 +145,7 @@ You can use the **unsubscribe** API to unsubscribe from a common event. ### Available APIs | API | Description| | ---------------------------------- | ------ | -| commonEvent.unsubscribe(subscriber: CommonEventSubscriber, callback?: AsyncCallback) | Unsubscribes from a common event.| +| unsubscribe(subscriber: CommonEventSubscriber, callback?: AsyncCallback) | Unsubscribes from a common event.| ### How to Develop 1. Import the **commonEvent** module. @@ -153,7 +154,7 @@ You can use the **unsubscribe** API to unsubscribe from a common event. import commonEvent from '@ohos.commonEvent'; ``` -2. Subscribe to a common event by following instructions in [Common Event Subscription Development](#Common-Event-Subscription-Development). +2. Subscribe to a common event by following instructions in [Common Event Subscription Development](#common-event-subscription-development). 3. Invoke the **unsubscribe** API in **CommonEvent** to unsubscribe from the common event. ```js diff --git a/en/application-dev/notification/notification-brief.md b/en/application-dev/notification/notification-brief.md index 8be39b2cc823398e4572a77469909f9fd06e2a5f..75237412fdf29d88843a9f23fa653f64f2de7c86 100644 --- a/en/application-dev/notification/notification-brief.md +++ b/en/application-dev/notification/notification-brief.md @@ -1,22 +1,19 @@ # Common Event and Notification Overview -The common event and notification module enables applications to publish messages to other applications, and receive messages from the system or other applications. These messages can be news push messages, advertisement notifications, or warning information. +The common event and notification module enables applications to publish messages to other applications, and receive messages from the system or other applications. These messages can be news push messages, advertisement notifications, warning information, and more. Common Event Service (CES) enables applications to publish, subscribe to, and unsubscribe from common events. Based on the sender type, common events are classified into system common events and custom common events. ![ces](figures/ces.png) - System common event: sent by the system based on system policies to the applications that have subscribed to the event. This type of event includes the screen-on/off events that the users are aware of and the system events published by key system services, such as USB device attachment or detachment, network connection, and system update events. - - Custom common event: customized by applications to be received by specific subscribers. This type of event is usually related to the service logic of the sender applications. - The Advanced Notification Service (ANS) enables applications to publish notifications. Below are some typical use cases for publishing notifications: +The Advanced Notification Service (ANS) enables applications to publish notifications. Below are some typical use cases for publishing notifications: - - Display received SMS messages and instant messages. - - - Display push messages of applications, such as advertisements, version updates, and news notifications. - - - Display ongoing events, such as music playback, navigation information, and download progress. +- Display received SMS messages and instant messages. +- Display push messages of applications, such as advertisements, version updates, and news notifications. +- Display ongoing events, such as music playback, navigation information, and download progress. Notifications are displayed in the notification panel. Uses can delete a notification or click the notification to trigger predefined actions. diff --git a/en/application-dev/quick-start/Readme-EN.md b/en/application-dev/quick-start/Readme-EN.md index 0a7533ea2389f74866ced1742937daeffe134fcc..9b89cfd83f8a3af29bda3fe76016d269561282cb 100644 --- a/en/application-dev/quick-start/Readme-EN.md +++ b/en/application-dev/quick-start/Readme-EN.md @@ -1,12 +1,22 @@ # Quick Start - - Getting Started - - [Preparations](start-overview.md) - - [Getting Started with eTS in Stage Model](start-with-ets-stage.md) - - [Getting Started with eTS in FA Model](start-with-ets-fa.md) - - [Getting Started with JavaScript in FA Model](start-with-js-fa.md) + - [Before You Start](start-overview.md) + - [Getting Started with ArkTS in Stage Model](start-with-ets-stage.md) + - [Getting Started with ArkTS in FA Model](start-with-ets-fa.md) + - [Getting Started with JavaScript in FA Model](start-with-js-fa.md) - Development Fundamentals - [Application Package Structure Configuration File (FA Model)](package-structure.md) - [Application Package Structure Configuration File (Stage Model)](stage-structure.md) - [SysCap](syscap.md) - - [HarmonyAppProvision Configuration File](app-provision-structure.md) + - [Resource Categories and Access](resource-categories-and-access.md) + - Learning ArkTS + - [Getting Started with ArkTS](arkts-get-started.md) + - ArkTS Syntax (Declarative UI) + - [Basic UI Description](arkts-basic-ui-description.md) + - State Management + - [Basic Concepts](arkts-state-mgmt-concepts.md) + - [State Management with Page-level Variables](arkts-state-mgmt-page-level.md) + - [State Management with Application-level Variables](arkts-state-mgmt-application-level.md) + - [Dynamic UI Element Building](arkts-dynamic-ui-elememt-building.md) + - [Rendering Control](arkts-rendering-control.md) + - [Restrictions and Extensions](arkts-restrictions-and-extensions.md) \ No newline at end of file diff --git a/en/application-dev/quick-start/arkts-basic-ui-description.md b/en/application-dev/quick-start/arkts-basic-ui-description.md new file mode 100644 index 0000000000000000000000000000000000000000..d20efe12859e944d9d78fb71688dc4aada729228 --- /dev/null +++ b/en/application-dev/quick-start/arkts-basic-ui-description.md @@ -0,0 +1,205 @@ +# Basic UI Description + +In ArkTS, you define a custom component by using decorators **@Component** and **@Entry** to decorate a data structure declared with the **struct** keyword. A custom component provides a **build** function, where you must write the basic UI description in chain call mode. For details about the UI description, see [UI Description Specifications](#ui-description-specifications). + +## Basic Concepts + +- struct: a data structure that can be used to implement custom components and cannot have inheritance. The **new** keyword can be omitted when initializing a struct. + +- Decorator: a special type of declaration that can be applied to classes, structures, or class attributes to add new functionality to them. Multiple decorators can be applied to the same target element and defined on a single line or multiple lines. It is recommended that the decorators be defined on multiple lines. + + ```ts + @Entry + @Component + struct MyComponent { + } + ``` + +- **build** function: a function that complies with the **Builder** API definition and is used to define the declarative UI description of components. A **build** function must be defined for custom components, and custom constructors are prohibited for custom components. + + ```ts + interface Builder { + build: () => void + } + ``` + +- **@Component**: a decorator applied to a struct to equip it with the component-based capability. The **build** method must be implemented for UI creation. + +- **@Entry**: a decorator applied to a struct to make it the entry to a page, which is rendered and displayed when the page is loaded. + +- **@Preview**: a decorator applied to struct to make it previewable in the DevEco Studio Previewer. The decorated component is created and displayed when the residing page is loaded. + + > **NOTE** + > + > In a single source file, you can use up to 10 **@Preview** decorators to decorate custom components. For details, see [Previewing ArkTS Components](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-previewing-app-service-0000001218760596#section146052489820). + +- Chain call: a syntax for configuring the attribute methods, event methods, and more of UI components by using the dot notation. + +## UI Description Specifications + +### Structs Without Parameters + +A struct without parameters is a component whose API definition has empty parentheses. No parameter needs to be passed to this type of component, for example, the **Divider** component in the following snippet: + +```ts +Column() { + Text('item 1') + Divider() + Text('item 2') +} +``` + +### Structs with Mandatory Parameters + +A struct with mandatory parameters is a component whose API definition expects parameters enclosed in the parentheses. You can use constants to assign values to the parameters. + +Sample code: + +- Set the mandatory parameter **src** of the **\** component as follows: + + ```ts + Image('https://xyz/test.jpg') + ``` + +- Set the mandatory parameter **content** of the **\** component as follows: + + ```ts + Text('test') + ``` + +You can use variables or expressions to assign values to parameters. The result type returned by an expression must meet the parameter type requirements. For details about the variables, see [State Management with Page-level Variables](arkts-state-mgmt-page-level.md) and [State Management with Application-level Variables](arkts-state-mgmt-application-level.md). For example, set a variable or expression to construct the **\** and **\** components: + +```ts +Image(this.imagePath) +Image('https://' + this.imageUrl) +Text(`count: ${this.count}`) +``` + +### Attribute Configuration + +Component attributes are configured using an attribute method, which follows the corresponding component and is bound to the component using the "**.**" operator. + +- Example of configuring the font size attribute of the **\** component: + + ```ts + Text('test') + .fontSize(12) + ``` + +- Example of configuring multiple attributes at the same time by using the "**.**" operator to implement chain call: + + ```ts + Image('test.jpg') + .alt('error.jpg') + .width(100) + .height(100) + ``` + +- Example of passing variables or expressions in addition to constants: + + ```ts + Text('hello') + .fontSize(this.size) + Image('test.jpg') + .width(this.count % 2 === 0 ? 100 : 200) + .height(this.offset + 100) + ``` + +- For attributes of built-in components, ArkUI also provides some predefined [enumeration types](../reference/arkui-ts/ts-appendix-enums.md), which you can pass as parameters to methods if they meet the parameter type requirements. For example, you can configure the font color and weight attributes of the **\** component as follows: + + ```ts + Text('hello') + .fontSize(20) + .fontColor(Color.Red) + .fontWeight(FontWeight.Bold) + ``` + +### Event Configuration + +Events supported by components are configured using event methods, which each follow the corresponding component and are bound to the component using the "**.**" operator. + +- Example of using a lambda expression to configure the event of a component: + + ```ts + Button('add counter') + .onClick(() => { + this.counter += 2 + }) + ``` + +- Example of using an anonymous function expression to configure the event of a component (**bind** must be used to ensure that the contained components are referenced by **this** in the function body): + + ```ts + Button('add counter') + .onClick(function () { + this.counter += 2 + }.bind(this)) + ``` + +- Example of using a component's member function to configure the event of the component: + + ```ts + myClickHandler(): void { + this.counter += 2 + } + + ... + + Button('add counter') + .onClick(this.myClickHandler) + ``` + +### Child Component Configuration + +For a component that supports child components, for example, a container component, add the UI descriptions of the child components inside parentheses. The **\**, **\**, **\**, **\**, and **\** components are all container components. + +- Simple example of the **\** component: + + ```ts + Column() { + Text('Hello') + .fontSize(100) + Divider() + Text(this.myText) + .fontSize(100) + .fontColor(Color.Red) + } + ``` + +- Example of nesting multiple child components in the **\** component: + + ```ts + Column() { + Row() { + Image('test1.jpg') + .width(100) + .height(100) + Button('click +1') + .onClick(() => { + console.info('+1 clicked!') + }) + } + + Divider() + Row() { + Image('test2.jpg') + .width(100) + .height(100) + Button('click +2') + .onClick(() => { + console.info('+2 clicked!') + }) + } + + Divider() + Row() { + Image('test3.jpg') + .width(100) + .height(100) + Button('click +3') + .onClick(() => { + console.info('+3 clicked!') + }) + } + } + ``` diff --git a/en/application-dev/quick-start/arkts-dynamic-ui-elememt-building.md b/en/application-dev/quick-start/arkts-dynamic-ui-elememt-building.md new file mode 100644 index 0000000000000000000000000000000000000000..a781f1d81c83a306c135b412b14ded55d032cb02 --- /dev/null +++ b/en/application-dev/quick-start/arkts-dynamic-ui-elememt-building.md @@ -0,0 +1,385 @@ +# Dynamic UI Element Building + +After you've created a custom component (as described in [Basic UI Description](arkts-basic-ui-description.md)), you can customize the internal UI structure for the component, by drawing on the capability of dynamic UI element building. + +## @Builder + +The **@Builder** decorator is used to decorate a function for quickly generating multiple layouts in a custom component. This function can be declared outside the **build** function and used in the **build** function or other **@Builder** decorated functions. The following example shows how to use **@Builder**. + +```ts +// xxx.ets +@Component +struct CompB { + @State CompValue: string = '' + + aboutToAppear() { + console.info('CompB aboutToAppear.') + } + + aboutToDisappear() { + console.info('CompB aboutToDisappear.') + } + + build() { + Column() { + Button(this.CompValue) + .margin(5) + } + } +} + +@Entry +@Component +struct CompA { + size1: number = 100 + @State CompValue1: string = "Hello,CompValue1" + @State CompValue2: string = "Hello,CompValue2" + @State CompValue3: string = "Hello,CompValue3" + + // Use the custom component CompB in the @Builder decorated function CompC. + @Builder CompC(value: string) { + CompB({ CompValue: value }) + } + + @Builder SquareText(label: string) { + Text(label) + .fontSize(18) + .width(1 * this.size1) + .height(1 * this.size1) + } + + // Use the @Builder decorated function SquareText in the @Builder decorated function RowOfSquareTexts. + @Builder RowOfSquareTexts(label1: string, label2: string) { + Row() { + this.SquareText(label1) + this.SquareText(label2) + } + .width(2 * this.size1) + .height(1 * this.size1) + } + + build() { + Column() { + Row() { + this.SquareText("A") + this.SquareText("B") + } + .width(2 * this.size1) + .height(1 * this.size1) + + this.RowOfSquareTexts("C", "D") + Column() { + // Use the @Builder decorated custom components three times. + this.CompC(this.CompValue1) + this.CompC(this.CompValue2) + this.CompC(this.CompValue3) + } + .width(2 * this.size1) + .height(2 * this.size1) + } + .width(2 * this.size1) + .height(2 * this.size1) + } +} +``` +![builder](figures/builder.PNG) + +## @BuilderParam8+ + +The **@BuilderParam** decorator is used to decorate the function type attributes (for example, **@BuilderParam noParam: () => void**) in a custom component. When the custom component is initialized, the attributes decorated by **@BuilderParam** must be assigned values. + +### Background + +In certain circumstances, you may need to add a specific function, such as a click-to-jump action, to a custom component. However, embedding an event method directly inside of the component will add the function to all places where the component is imported. This is where the **@BuilderParam** decorator comes into the picture. When initializing a custom component, you can assign a **@Builder** decorated method to the **@BuilderParam** decorated attribute, thereby adding the specific function to the custom component. + +### Component Initialization Through Parameters + +When initializing a custom component through parameters, assign a **@Builder** decorated method to the **@BuilderParam** decorated attribute — **content**, and call the value of **content** in the custom component. If no parameter is passed when assigning a value to the **@BuilderParam** decorated attribute (for example, **noParam: this.specificNoParam**), define the type of the attribute as a function without a return value (for example, **@BuilderParam noParam: () => void**). If any parameter is passed when assigning a value to the **@BuilderParam** decorated attribute (for example, **withParam: this.SpecificWithParam('WithParamA')**), define the type of the attribute as **any** (for example, **@BuilderParam withParam: any**). + +```ts +// xxx.ets +@Component +struct CustomContainer { + header: string = '' + @BuilderParam noParam: () => void + @BuilderParam withParam: any + footer: string = '' + + build() { + Column() { + Text(this.header) + .fontSize(30) + this.noParam() + this.withParam() + Text(this.footer) + .fontSize(30) + } + } +} + +@Entry +@Component +struct CustomContainerUser { + @Builder specificNoParam() { + Column() { + Text('noParam').fontSize(30) + } + } + + @Builder SpecificWithParam(label: string) { + Column() { + Text(label).fontSize(30) + } + } + + build() { + Column() { + CustomContainer({ + header: 'HeaderA', + noParam: this.specificNoParam, + withParam: this.SpecificWithParam('WithParamA'), + footer: 'FooterA' + }) + Divider() + .strokeWidth(3) + .margin(10) + CustomContainer({ + header: 'HeaderB', + noParam: this.specificNoParam, + withParam: this.SpecificWithParam('WithParamB'), + footer: 'FooterB' + }) + } + } +} +``` + +![builder1](figures/builder1.PNG) + +### Component Initialization Through Trailing Closure + +In a custom component, the **@BuilderParam** decorated attribute can be initialized using a trailing closure. During initialization, the component name is followed by a pair of braces ({}) to form a trailing closure (**CustomContainer(){}**). You can consider a trailing closure as a container and add content to it. For example, you can add a component (**{Column(){...}**) to the closure. The syntax of the closure is the same as that of **build**. In this scenario, the custom component has one and only one **@BuilderParam** decorated attribute. + +Example: Add a **\** component and a click event to the closure, and call the **specificParam** method decorated by **@Builder** in the new **\** component. After the **\** component is clicked, the value of the **CustomContainer** component's **header** attribute will change from **header** to **changeHeader**. When the component is initialized, the content of the trailing closure will be assigned to the **closer** attribute decorated by **@BuilderParam**. + +```ts +// xxx.ets +@Component +struct CustomContainer { + header: string = '' + @BuilderParam closer: () => void + + build() { + Column() { + Text(this.header) + .fontSize(30) + this.closer() + } + } +} + +@Builder function specificParam(label1: string, label2: string) { + Column() { + Text(label1) + .fontSize(30) + Text(label2) + .fontSize(30) + } +} + +@Entry +@Component +struct CustomContainerUser { + @State text: string = 'header' + + build() { + Column() { + CustomContainer({ + header: this.text, + }) { + Column() { + specificParam('testA', 'testB') + }.backgroundColor(Color.Yellow) + .onClick(() => { + this.text = 'changeHeader' + }) + } + } + } +} +``` + +![builder2](figures/builder2.gif) + +## @Styles + +The **@Styles** decorator helps avoid repeated style setting, by extracting multiple style settings into one method. When declaring a component, you can invoke this method and use the **@Styles** decorator to quickly define and reuse the custom styles of a component. **@Styles** supports only universal attributes. + +**@Styles** can be defined inside or outside a component declaration. When it is defined outside a component declaration, the component name must be preceded by the keyword **function**. + +```ts +// xxx.ets +@Styles function globalFancy () { + .width(150) + .height(100) + .backgroundColor(Color.Pink) +} + +@Entry +@Component +struct FancyUse { + @Styles componentFancy() { + .width(100) + .height(200) + .backgroundColor(Color.Yellow) + } + + build() { + Column({ space: 10 }) { + Text('FancyA') + .globalFancy() + .fontSize(30) + Text('FancyB') + .globalFancy() + .fontSize(20) + Text('FancyC') + .componentFancy() + .fontSize(30) + Text('FancyD') + .componentFancy() + .fontSize(20) + } + } +} +``` + +![styles](figures/styles.PNG) + +**@Styles** can also be used inside the **[StateStyles](../reference/arkui-ts/ts-universal-attributes-polymorphic-style.md)** attribute declaration of a component, to assign state-specific attributes to the component. + +In **StateStyles**, **@Styles** decorated methods defined outside the component can be directly called, while those defined inside can be called only with the keyword **this**. + +```ts +// xxx.ets +@Styles function globalFancy () { + .width(120) + .height(120) + .backgroundColor(Color.Green) +} + +@Entry +@Component +struct FancyUse { + @Styles componentFancy() { + .width(80) + .height(80) + .backgroundColor(Color.Red) + } + + build() { + Row({ space: 10 }) { + Button('Fancy') + .stateStyles({ + normal: { + .width(100) + .height(100) + .backgroundColor(Color.Blue) + }, + disabled: this.componentFancy, + pressed: globalFancy + }) + } + } +} +``` + +![styles1](figures/styles1.gif) + +## @Extend + +The **@Extend** decorator adds new attribute methods to built-in components, such as **\**, **\**, and **\