You need to sign in or sign up before continuing.
提交 9935e74c 编写于 作者: C chennian

API参考内容优化

Signed-off-by:chennian<chennian1@huawei.com>
Signed-off-by: Nchennian <chennian1@huawei.com>
......@@ -231,7 +231,7 @@ 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-medialibrary.md @qinxiaowang
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
......@@ -366,6 +366,7 @@ zh-cn/application-dev/reference/js-service-widget-ui @HelloCrease
zh-cn/application-dev/website.md @zengyawen
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-userfilemanager.md @qinxiaowang
zh-cn/application-dev/reference/apis/js-apis-cryptoFramework.md @zengyawen
zh-cn/application-dev/reference/apis/Readme-CN.md @zengyawen
zh-cn/application-dev/file-management/ @qinxiaowang
\ No newline at end of file
......@@ -5,7 +5,7 @@ An ability is the abstraction of a functionality that an application can provide
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.
- Stage model, which is introduced since API version 9. In the stage model, there is `PageAbility` 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.
......
......@@ -12,6 +12,7 @@ The Feature Ability (FA) model applies to application development using API vers
## 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)
......@@ -26,3 +27,9 @@ Currently, the **app.js** file provides only the **onCreate** and **onDestroy**
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)
## 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/package-structure.md).
......@@ -49,6 +49,8 @@ The ability and ability stage lifecycles are the rudiments of the basic process
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.
There are two lifecycle states related to **WindowStage** in **Ability**: **onWindowStageCreate** and **onWindowStageDestroy**. They are valid only for devices with the window 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
......@@ -58,7 +60,7 @@ Abilities can be started in any of the following modes:
+ **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.
+ **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 **Launcher Recent**.
......@@ -92,6 +94,12 @@ All OpenHarmony applications are designed to meet the single-process model. In t
- Render process: created for the WebView and used to load the WebView rendering library.
The following figure shows the process model of an application.
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).
![stageprocessmodel](figures/stageprocessmodel.png)
For details about how to configure the application package structure of the stage model, see [Application Package Structure Configuration File (Stage Model)](../quick-start/stage-structure.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.|
......@@ -32,10 +32,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);
// Keep the service process running.
......
# Device Management Development
# Data Management Development
......
......@@ -381,6 +381,53 @@ context.getDisplayOrientation().then((data) => {
});
```
## Context.getExternalCacheDir
getExternalCacheDir(callback: AsyncCallback\<string>): void
Obtains the external cache directory of the application. This API uses an asynchronous callback to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Parameters**
| Name | Type | Mandatory | Description |
| -------- | ---------------------- | ---- | ------------------ |
| callback | AsyncCallback\<string> | Yes | Callback used to return the absolute path of the cache directory.|
**Example**
```js
import featureAbility from '@ohos.ability.featureAbility'
var context = featureAbility.getContext();
context.getExternalCacheDir()
```
## Context.getExternalCacheDir
getExternalCacheDir(): Promise\<string>;
Obtains the external cache directory of the application. This API uses a promise to return the result.
**System capability**: SystemCapability.Ability.AbilityRuntime.Core
**Return value**
| Type | Description |
| ---------------- | ---------------- |
| Promise\<string> | Promise used to return the absolute path of the cache directory.|
**Example**
```js
import featureAbility from '@ohos.ability.featureAbility'
var context = featureAbility.getContext();
context.getExternalCacheDir().then((data) => {
console.info("=======================>getExternalCacheDirCallback====================>");
console.info("====>data====>" + JSON.stringify(data));
});
```
## Context.setDisplayOrientation<sup>7+</sup>
setDisplayOrientation(orientation: bundle.DisplayOrientation, callback: AsyncCallback\<void>): void
......
......@@ -319,7 +319,7 @@ Checks whether the called number is an emergency number based on the specified p
**Example**
```js
call.isEmergencyPhoneNumber("112", {slotId: 1}, (err, value) => {
call.isEmergencyPhoneNumber("112", {slotId: 1}, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......@@ -468,9 +468,7 @@ The phone number must match the specified country code. For example, for a China
**Example**
```js
call.formatPhoneNumberToE164("138xxxxxxxx",{
countryCode: "CN"
}, (err, data) => {
call.formatPhoneNumberToE164("138xxxxxxxx", "CN", (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......@@ -504,9 +502,7 @@ All country codes are supported.
**Example**
```js
let promise = call.formatPhoneNumberToE164("138xxxxxxxx", {
countryCode: "CN"
});
let promise = call.formatPhoneNumberToE164("138xxxxxxxx", "CN");
promise.then(data => {
console.log(`formatPhoneNumberToE164 success, promise: data->${JSON.stringify(data)}`);
}).catch(err => {
......@@ -1700,7 +1696,7 @@ This is a system API.
**Example**
```js
isNewCallAllowedcall.on('mmiCodeResult', (err, data) => {
call.on('mmiCodeResult', (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......@@ -2069,9 +2065,6 @@ This is a system API.
**Example**
```js
let callTransferTyp={
CallTransferType: 1
}
call.getCallTransferInfo(0, callTransferTyp, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
......@@ -2104,10 +2097,7 @@ This is a system API.
**Example**
```js
let callTransferTyp={
CallTransferType: 1
}
let promise = call.getCallTransferInfo(0, callTransferTyp);
let promise = call.getCallTransferInfo(0, call.CallTransferType.TRANSFER_TYPE_BUSY);
promise.then(data => {
console.log(`getCallTransferInfo success, promise: data->${JSON.stringify(data)}`);
}).catch(err => {
......@@ -2396,7 +2386,7 @@ This is a system API.
let audioDeviceOptions={
bluetoothAddress: "IEEE 802-2014"
}
call.setAudioDevice(1, bluetoothAddress, (err, value) => {
call.setAudioDevice(1, audioDeviceOptions, (err, value) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......@@ -2460,7 +2450,10 @@ This is a system API.
**Example**
```js
call.joinConference(1, "138XXXXXXXX", (err, data) => {
let callNumberList: Array<string> = [
"138XXXXXXXX"
];
call.joinConference(1, callNumberList, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......@@ -2491,7 +2484,10 @@ This is a system API.
**Example**
```js
let promise = call.joinConference(1, "138XXXXXXXX");
let callNumberList: Array<string> = [
"138XXXXXXXX"
];
let promise = call.joinConference(1, callNumberList);
promise.then(data => {
console.log(`joinConference success, promise: data->${JSON.stringify(data)}`);
}).catch(err => {
......
......@@ -304,11 +304,8 @@ hiAppEvent.addWatcher({
console.error("holder is null");
return;
}
while (true) {
let eventPkg = holder.takeNext();
if (eventPkg == null) {
return;
}
let eventPkg = null;
while ((eventPkg = holder.takeNext()) != null) {
console.info("eventPkg.packageId=" + eventPkg.packageId);
console.info("eventPkg.row=" + eventPkg.row);
console.info("eventPkg.size=" + eventPkg.size);
......@@ -324,16 +321,15 @@ let holder = hiAppEvent.addWatcher({
name: "watcher2",
});
if (holder != null) {
let eventPkg = holder.takeNext();
if (eventPkg == null) {
return;
}
let eventPkg = null;
while ((eventPkg = holder.takeNext()) != null) {
console.info("eventPkg.packageId=" + eventPkg.packageId);
console.info("eventPkg.row=" + eventPkg.row);
console.info("eventPkg.size=" + eventPkg.size);
for (const eventInfo of eventPkg.data) {
console.info("eventPkg.data=" + eventInfo);
}
}
}
```
......@@ -417,6 +413,9 @@ Sets the data size threshold for fetching an application event package. The defa
**Example**
```js
let holder = hiAppEvent.addWatcher({
name: "watcher",
});
holder.setSize(1000);
```
......@@ -429,6 +428,9 @@ Extracts subscription event data based on the configured data size threshold. If
**Example**
```js
let holder = hiAppEvent.addWatcher({
name: "watcher",
});
let eventPkg = holder.takeNext();
```
......
......@@ -30,9 +30,10 @@ This API is defined but not implemented in OpenHarmony 3.1 Release.
**Example**
```js
let nativeHeapSize = hidebug.getNativeHeapSize();
```
```js
let nativeHeapSize = hidebug.getNativeHeapSize();
```
## hidebug.getNativeHeapAllocatedSize
......@@ -45,17 +46,18 @@ This API is defined but not implemented in OpenHarmony 3.1 Release.
**System capability**: SystemCapability.HiviewDFX.HiProfiler.HiDebug
**Return value**
| Type | Description |
| ------ | --------------------------------- |
| bigint | Size of the allocated native heap memory, in kB.|
**Example**
```js
let nativeHeapAllocatedSize = hidebug.getNativeHeapAllocatedSize();
```
```js
let nativeHeapAllocatedSize = hidebug.getNativeHeapAllocatedSize();
```
## hidebug.getNativeHeapFreeSize
......@@ -68,17 +70,18 @@ This API is defined but not implemented in OpenHarmony 3.1 Release.
**System capability**: SystemCapability.HiviewDFX.HiProfiler.HiDebug
**Return value**
| Type | Description |
| ------ | ------------------------------- |
| bigint | Size of the free native heap memory, in kB.|
**Example**
```js
let nativeHeapFreeSize = hidebug.getNativeHeapFreeSize();
```
```js
let nativeHeapFreeSize = hidebug.getNativeHeapFreeSize();
```
## hidebug.getPss
......@@ -89,17 +92,18 @@ Obtains the PSS of this process.
**System capability**: SystemCapability.HiviewDFX.HiProfiler.HiDebug
**Return value**
| Type | Description |
| ------ | ------------------------- |
| bigint | PSS of the process, in kB.|
**Example**
```js
let pss = hidebug.getPss();
```
```js
let pss = hidebug.getPss();
```
## hidebug.getSharedDirty
......@@ -110,17 +114,18 @@ Obtains the size of the shared dirty memory of this process.
**System capability**: SystemCapability.HiviewDFX.HiProfiler.HiDebug
**Return value**
| Type | Description |
| ------ | -------------------------- |
| bigint | Size of the shared dirty memory of the process, in kB.|
**Example**
```js
let sharedDirty = hidebug.getSharedDirty();
```
```js
let sharedDirty = hidebug.getSharedDirty();
```
## hidebug.getPrivateDirty<sup>9+<sup>
......@@ -130,8 +135,8 @@ Obtains the size of the private dirty memory of this process.
**System capability**: SystemCapability.HiviewDFX.HiProfiler.HiDebug
**Return value**
| Type | Description |
| ------ | -------------------------- |
| bigint | Size of the private dirty memory of the process, in kB.|
......@@ -152,17 +157,18 @@ For example, if the CPU usage is **50%**, **0.5** is returned.
**System capability**: SystemCapability.HiviewDFX.HiProfiler.HiDebug
**Return value**
| Type | Description |
| ------ | -------------------------- |
| number | CPU usage of the process.|
**Example**
```js
let cpuUsage = hidebug.getCpuUsage();
```
```js
let cpuUsage = hidebug.getCpuUsage();
```
## hidebug.startProfiling
......@@ -189,7 +195,6 @@ hidebug.stopProfiling();
```
## hidebug.stopProfiling
stopProfiling() : void
......@@ -245,6 +250,7 @@ This is a system API and cannot be called by third-party applications.
| serviceid | number | Yes | ID of the system service. |
**Return value**
| Type | Description |
| ------ | -------------------------- |
| string | Absolute path of the file that contains the service information to dump. |
......
......@@ -60,7 +60,8 @@ Writes event information to the event file. This API uses an asynchronous callba
```js
import hiSysEvent from '@ohos.hiSysEvent';
hiSysEvent.write({
try {
hiSysEvent.write({
domain: "RELIABILITY",
name: "STACK",
eventType: hiSysEvent.EventType.FAULT,
......@@ -71,9 +72,12 @@ hiSysEvent.write({
PROCESS_NAME: "syseventservice",
MSG: "no msg."
}
}, (err, val) => {
}, (err, val) => {
// do something here.
})
})
} catch (error) {
console.error(`error code: ${error.code}, error msg: ${error.message}`);
}
```
......@@ -102,7 +106,8 @@ Writes event information to the event file. This API uses a promise to return th
```js
import hiSysEvent from '@ohos.hiSysEvent';
hiSysEvent.write({
try {
hiSysEvent.write({
domain: "RELIABILITY",
name: "STACK",
eventType: hiSysEvent.EventType.FAULT,
......@@ -113,15 +118,18 @@ hiSysEvent.write({
PROCESS_NAME: "syseventservice",
MSG: "no msg."
}
}).then(
}).then(
(val) => {
// do something here.
}
).catch(
).catch(
(err) => {
// do something here.
}
)
)
} catch (error) {
console.error(`error code: ${error.code}, error msg: ${error.message}`);
}
```
## RuleType
......@@ -177,12 +185,6 @@ Adds a watcher for event subscription.
| ------ | ----------------------------- | ---- | ------------------------ |
| watcher | [Watcher](#watcher) | Yes| Watcher for event subscription.|
**Return value**
| Type | Description|
| ------- | -------------------------------------------------- |
| number | Event subscription result.<br>- **0**: Event subscription is successful.<br>- A value smaller than **0**: Event subscription has failed.|
**Example**
```js
......@@ -202,7 +204,11 @@ let watcher = {
// do something here.
}
}
let ret = hiSysEvent.addWatcher(watcher)
try {
hiSysEvent.addWatcher(watcher)
} catch (error) {
console.error(`error code: ${error.code}, error msg: ${error.message}`);
}
```
## hiSysEvent.removeWatcher
......@@ -221,12 +227,6 @@ Removes a watcher used for event subscription.
| ------ | ------------- | ---- | ------------------------ |
| watcher | [Watcher](#watcher) | Yes| Watcher for event subscription.|
**Return value**
| Type | Description|
| ------- | ----------------------------------------------------------- |
| number | Result of removing the watcher.<br>- **0**: Removing the watcher is successful.<br>- A value smaller than **0**: Removing the watcher has failed.|
**Example**
```js
......@@ -246,8 +246,12 @@ let watcher = {
// do something here.
}
}
let ret = hiSysEvent.addWatcher(watcher)
hiSysEvent.removeWatcher(watcher)
try {
hiSysEvent.addWatcher(watcher)
hiSysEvent.removeWatcher(watcher)
} catch (error) {
console.error(`error code: ${error.code}, error msg: ${error.message}`);
}
```
## QueryArg
......@@ -281,7 +285,7 @@ Defines an event query instance.
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| onQuery | function | Yes| Callback of queried events: (infos: [SysEventInfo](#syseventinfo)[], seqs: number[]) => void|
| onQuery | function | Yes| Callback of queried events: (infos: [SysEventInfo](#syseventinfo)[]) => void|
| onComplete | function | Yes| Callback of query result statistics: (reason: number, total: number) => void|
## hiSysEvent.query
......@@ -302,18 +306,13 @@ Queries system events.
| rules | [QueryRule](#queryrule)[] | Yes | Array of event query rules.|
| querier | [Querier](#querier) | Yes | Event query instance.|
**Return value**
| Type | Description |
| ------- | ----------------------------------------------------------- |
| number | Event query result.<br>- **0**: Event query is successful.<br>- A value smaller than **0**: Event query has failed.|
**Example**
```js
import hiSysEvent from '@ohos.hiSysEvent';
hiSysEvent.write({
try {
hiSysEvent.write({
domain: "RELIABILITY",
name: "STACK",
eventType: hiSysEvent.EventType.FAULT,
......@@ -324,22 +323,25 @@ hiSysEvent.write({
PROCESS_NAME: "syseventservice",
MSG: "no msg."
}
}, (err, val) => {
}, (err, val) => {
// do something here.
})
hiSysEvent.query({
})
hiSysEvent.query({
beginTime: -1,
endTime: -1,
maxEvents: 5,
}, [{
}, [{
domain: "RELIABILITY",
names: ["STACK"],
}], {
onQuery: function (infos, seqs) {
}], {
onQuery: function (infos) {
// do something here.
},
onComplete: function(reason, total) {
// do something here.
}
})
})
} catch (error) {
console.error(`error code: ${error.code}, error msg: ${error.message}`);
}
```
......@@ -71,7 +71,7 @@ Defines a **HiTraceId** object.
## hiTraceChain.begin
begin(name: string, flags: number = HiTraceFlag.DEFAULT): HiTraceId
begin(name: string, flags?: number): HiTraceId
Starts call chain tracing. This API works in synchronous manner.
......@@ -82,7 +82,7 @@ Starts call chain tracing. This API works in synchronous manner.
| Name | Type | Mandatory | Description |
| -------- | -------- | -------- | -------- |
| name | string | Yes| Traced service name. |
| flags | number | Yes| Trace flag combination. For details, see [HiTraceFlag](#hitraceflag). |
| flags | number | No| Trace flag combination. For details, see [HiTraceFlag](#hitraceflag). |
**Return Value**
......@@ -113,7 +113,7 @@ Stops call chain tracing. This API works in synchronous manner.
**Example**
```js
let asyncTraceId = hiTraceChain.begin("business");
let asyncTraceId = hiTraceChain.begin("business", hiTraceChain.HiTraceFlag.DEFAULT);
// End the call chain tracing after the service logic is executed for several times.
hiTraceChain.end(asyncTraceId);
```
......@@ -135,7 +135,7 @@ Obtains the trace ID. This API works in synchronous manner.
**Example**
```js
let traceId = hiTraceChain.begin("business");
let traceId = hiTraceChain.begin("business", hiTraceChain.HiTraceFlag.DEFAULT);
// Obtain the current trace ID after the service logic is executed for several times.
let curTraceId = hiTraceChain.getId();
```
......@@ -158,7 +158,7 @@ Sets a trace ID. This API works in synchronous manner.
```js
let asyncTraceId;
let traceId = hiTraceChain.begin("business");
let traceId = hiTraceChain.begin("business", hiTraceChain.HiTraceFlag.DEFAULT);
// Set the current trace ID after the service logic is executed for several times.
hiTraceChain.setId(asyncTraceId);
```
......@@ -174,7 +174,7 @@ Clears the trace ID. This API works in synchronous manner.
**Example**
```js
let traceId = hiTraceChain.begin("business");
let traceId = hiTraceChain.begin("business", hiTraceChain.HiTraceFlag.DEFAULT);
// Clear the current trace ID after the service logic is executed for several times.
hiTraceChain.clearId();
```
......@@ -196,7 +196,7 @@ Creates a trace span. This API works in synchronous manner.
**Example**
```js
let traceId = hiTraceChain.begin("business");
let traceId = hiTraceChain.begin("business", hiTraceChain.HiTraceFlag.DEFAULT);
// Create a trace span after the service logic is executed for several times.
let spanTraceId = hiTraceChain.createSpan();
```
......@@ -249,7 +249,7 @@ Checks whether a **HiTraceId** instance is valid. This API works in synchronous
**Example**
```js
let traceId = hiTraceChain.begin("business");
let traceId = hiTraceChain.begin("business", hiTraceChain.HiTraceFlag.DEFAULT);
let traceIdIsvalid = hiTraceChain.isValid(traceId);
```
......@@ -291,6 +291,7 @@ Enables the specified trace flag in the **HiTraceId** instance. This API works i
**System capability**: SystemCapability.HiviewDFX.HiTrace
**Parameters**
| Name | Type | Mandatory | Description |
| -------- | -------- | -------- | -------- |
| id | [HiTraceId](#hitraceid) | Yes | **HiTraceId** instance. |
......
......@@ -68,7 +68,7 @@ This is a system API.
**Example**
```
let keyOptions = {preKeys: [], finalKey: 3, isFinalKeyDown: true, finalKeyDownDuration: 0}
let keyOptions = {preKeys: [], finalKey: 18, isFinalKeyDown: true, finalKeyDownDuration: 0}
let callback = function(keyOptions) {
console.info("preKeys: " + keyOptions.preKeys, "finalKey: " + keyOptions.finalKey,
"isFinalKeyDown: " + keyOptions.isFinalKeyDown, "finalKeyDownDuration: " + keyOptions.finalKeyDownDuration)
......
......@@ -404,7 +404,7 @@ Provides the device capability.
| currencyDisplay | string | Yes | Yes | Currency display mode. The value can be **symbol**, **narrowSymbol**, **code**, or **name**.|
| unit | string | Yes | Yes | Unit name, for example, **meter**, **inch**, or **hectare**. |
| unitDisplay | string | Yes | Yes | Unit display format. The value can be **long**, **short**, or **narrow**.|
| unitUsage<sup>8+</sup> | string | Yes | Yes | Unit usage scenario. The value can be any of the following: **default**, **area-land-agricult**, **area-land-commercl**, **area-land-residntl**, **length-person**, **length-person-small**, **length-rainfall**, **length-road**, **length-road-small**, **length-snowfall**, **length-vehicle**, **length-visiblty**, **length-visiblty-small**, **length-person-informal**, **length-person-small-informal**, **length-road-informal**, **speed-road-travel**, **speed-wind**, **temperature-person**, **temperature-weather**, **volume-vehicle-fuel**.|
| unitUsage | string | Yes | Yes | Unit usage scenario. The value can be any of the following: **default**, **area-land-agricult**, **area-land-commercl**, **area-land-residntl**, **length-person**, **length-person-small**, **length-rainfall**, **length-road**, **length-road-small**, **length-snowfall**, **length-vehicle**, **length-visiblty**, **length-visiblty-small**, **length-person-informal**, **length-person-small-informal**, **length-road-informal**, **speed-road-travel**, **speed-wind**, **temperature-person**, **temperature-weather**, **volume-vehicle-fuel**.|
| signDisplay | string | Yes | Yes | Number sign display format. The value can be **auto**, **never**, **always**, or **expectZero**.|
| compactDisplay | string | Yes | Yes | Compact display format. The value can be **long** or **short**. |
| notation | string | Yes | Yes | Number formatting specification. The value can be **standard**, **scientific**, **engineering**, or **compact**.|
......
......@@ -96,7 +96,7 @@ import {KeyCode} from '@ohos.multimodalInput.keyCode'
| KEYCODE_EQUALS | number | Yes| No| Key =|
| KEYCODE_LEFT_BRACKET | number | Yes| No| Key [|
| KEYCODE_RIGHT_BRACKET | number | Yes| No| Key ]|
| KEYCODE_BACKSLASH | number | Yes| No| Key \|
| KEYCODE_BACKSLASH | number | Yes| No| Key \\|
| KEYCODE_SEMICOLON | number | Yes| No| Key ;|
| KEYCODE_APOSTROPHE | number | Yes| No| Key ' |
| KEYCODE_SLASH | number | Yes| No| Key /|
......
......@@ -47,7 +47,7 @@ Obtains the default active data network. This API uses a promise to return the r
**System capability**: SystemCapability.Communication.NetManager.Core
**Return Value**
**Return value**
| Type | Description |
| --------------------------------- | ------------------------------------- |
......@@ -92,7 +92,7 @@ Checks whether the default data network is activated. This API uses a promise to
**System capability**: SystemCapability.Communication.NetManager.Core
**Return Value**
**Return value**
| Type | Description |
| ----------------- | ----------------------------------------------- |
......@@ -117,6 +117,7 @@ Obtains the list of all active data networks. This API uses an asynchronous call
**System capability**: SystemCapability.Communication.NetManager.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| callback | AsyncCallback&lt;Array&lt;[NetHandle](#nethandle)&gt;&gt; | Yes| Callback used to return the result.|
......@@ -141,7 +142,8 @@ Obtains the list of all active data networks. This API uses a promise to return
**System capability**: SystemCapability.Communication.NetManager.Core
**Return Value**
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;Array&lt;[NetHandle](#nethandle)&gt;&gt; | Promise used to return the result.|
......@@ -198,7 +200,7 @@ Obtains connection properties of the network corresponding to **netHandle**. Thi
| --------- | ----------------------- | ---- | ---------------- |
| netHandle | [NetHandle](#nethandle) | Yes | Handle of the data network.|
**Return Value**
**Return value**
| Type | Description |
| ------------------------------------------------------- | --------------------------------- |
......@@ -258,7 +260,7 @@ Obtains capability information of the network corresponding to **netHandle**. Th
| --------- | ----------------------- | ---- | ---------------- |
| netHandle | [NetHandle](#nethandle) | Yes | Handle of the data network.|
**Return Value**
**Return value**
| Type | Description |
| --------------------------------------------- | --------------------------------- |
......@@ -285,6 +287,7 @@ Reports connection of the data network. This API uses an asynchronous callback t
**System capability**: SystemCapability.Communication.NetManager.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| netHandle | [NetHandle](#nethandle) | Yes| Handle of the data network. For details, see [NetHandle](#nethandle).|
......@@ -312,11 +315,13 @@ Reports connection of the data network. This API uses a promise to return the re
**System capability**: SystemCapability.Communication.NetManager.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| netHandle | [NetHandle](#nethandle) | Yes| Handle of the data network. For details, see [NetHandle](#nethandle).|
**Return Value**
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;void&gt; | Promise used to return the result.|
......@@ -343,6 +348,7 @@ Reports disconnection of the data network. This API uses an asynchronous callbac
**System capability**: SystemCapability.Communication.NetManager.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| netHandle | [NetHandle](#nethandle) | Yes| Handle of the data network. For details, see [NetHandle](#nethandle).|
......@@ -370,11 +376,13 @@ Reports disconnection of the data network. This API uses a promise to return the
**System capability**: SystemCapability.Communication.NetManager.Core
**Parameters**
| Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- |
| netHandle | [NetHandle](#nethandle) | Yes| Handle of the data network. For details, see [NetHandle](#nethandle).|
**Return Value**
**Return value**
| Type| Description|
| -------- | -------- |
| Promise&lt;void&gt; | Promise used to return the result.|
......@@ -432,7 +440,7 @@ Resolves the host name by using the default network to obtain all IP addresses.
| ------ | ------ | ---- | ------------------ |
| host | string | Yes | Host name to be resolved.|
**Return Value**
**Return value**
| Type | Description |
| ------------------------------------------- | ----------------------------- |
......@@ -561,7 +569,7 @@ Obtains the handle of the network specified by **netSpecifier**.
| netSpecifier | [NetSpecifier](#netspecifier) | No | Network specifier. If this parameter is not set, the default network is used. |
| timeout | number | No | Timeout interval for obtaining the network specified by **netSpecifier**. This parameter is valid only when **netSpecifier** is set.|
**Return Value**
**Return value**
| Type | Description |
| ------------------------------- | -------------------- |
......@@ -829,7 +837,7 @@ Resolves the host name by using the corresponding network to obtain all IP addre
| ------ | ------ | ---- | ------------------ |
| host | string | Yes | Host name to be resolved.|
**Return Value**
**Return value**
| Type | Description |
| ------------------------------------------- | ----------------------------- |
......@@ -891,7 +899,7 @@ Resolves the host name by using the corresponding network to obtain the first IP
| ------ | ------ | ---- | ------------------ |
| host | string | Yes | Host name to be resolved.|
**Return Value**
**Return value**
| Type | Description |
| ----------------------------------- | ------------------------------- |
......
......@@ -1100,12 +1100,12 @@ Sets the network selection mode. This API uses an asynchronous callback to retur
let networkInformation={
operatorName: "China Mobile",
operatorNumeric: "898600",
state: 1,
state: radio.NetworkInformationState.NETWORK_AVAILABLE,
radioTech: "CS"
}
let networkSelectionModeOptions={
slotid: 0,
selectMode: 1,
slotId: 0,
selectMode: radio.NetworkSelectionMode.NETWORK_SELECTION_AUTOMATIC,
networkInformation: networkInformation,
resumeSelection: true
}
......@@ -1144,12 +1144,12 @@ Sets the network selection mode. This API uses a promise to return the result.
let networkInformation={
operatorName: "China Mobile",
operatorNumeric: "898600",
state: 1,
state: radio.NetworkInformationState.NETWORK_AVAILABLE,
radioTech: "CS"
}
let networkSelectionModeOptions={
slotid: 0,
selectMode: 1,
slotId: 0,
selectMode: radio.NetworkSelectionMode.NETWORK_SELECTION_AUTOMATIC,
networkInformation: networkInformation,
resumeSelection: true
}
......@@ -1190,7 +1190,7 @@ radio.getNetworkSearchInformation(0, (err, data) => {
## radio.getNetworkSearchInformation
getNetworkSearchInformation\(slotId: number\): Promise<void\>
getNetworkSearchInformation\(slotId: number\): Promise<NetworkSearchResult\>
Obtains network search information for the SIM card in the specified slot. This API uses a promise to return the result.
......@@ -1586,7 +1586,7 @@ radio.getPreferredNetwork(0, (err, data) => {
## radio.getPreferredNetwork<sup>8+</sup>
getPreferredNetwork(slotId: number): Promise<void\>
getPreferredNetwork(slotId: number): Promise<PreferredNetworkMode\>
Obtains the preferred network for the SIM card in the specified slot. This API uses a promise to return the result.
......@@ -1642,7 +1642,7 @@ Obtains the IMS registration status of the specified IMS service type for the SI
**Example**
```js
radio.getImsRegInfo(0, 1, (err, data) => {
radio.getImsRegInfo(0, radio.ImsServiceType.TYPE_VIDEO, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......@@ -1675,7 +1675,7 @@ Obtains the IMS registration status of the specified IMS service type for the SI
**Example**
```js
let promise = radio.getImsRegInfo(0, 1);
let promise = radio.getImsRegInfo(0, radio.ImsServiceType.TYPE_VIDEO);
promise.then(data => {
console.log(`getImsRegInfo success, promise: data->${JSON.stringify(data)}`);
}).catch(err => {
......@@ -1707,7 +1707,7 @@ Enables listening for **imsRegStateChange** events for the SIM card in the speci
**Example**
```js
radio.on('imsRegStateChange', 0, 1, (err, data) => {
radio.on('imsRegStateChange', 0, radio.ImsServiceType.TYPE_VIDEO, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......@@ -1736,7 +1736,7 @@ Disables listening for **imsRegStateChange** events for the SIM card in the spec
**Example**
```js
radio.off('imsRegStateChange', 0, 1, (err, data) => {
radio.off('imsRegStateChange', 0, radio.ImsServiceType.TYPE_VIDEO, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......
......@@ -589,7 +589,7 @@ Obtains the account information list of the active SIM card. This API uses an as
**Example**
```js
sim.getActiveSimAccountInfoList(0, (err, data) => {
sim.getActiveSimAccountInfoList((err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......@@ -710,7 +710,7 @@ Sets a display name for the SIM card in the specified slot. This API uses an asy
**Example**
```js
const name='China Mobile';
let name = 'China Mobile';
sim.setShowName(0, name, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
......@@ -744,7 +744,7 @@ Sets a display name for the SIM card in the specified slot. This API uses a prom
**Example**
```js
const name='China Mobile';
let name = 'China Mobile';
let promise = sim.setShowName(0, name);
promise.then(data => {
console.log(`setShowName success, promise: data->${JSON.stringify(data)}`);
......@@ -1096,9 +1096,9 @@ Sets the lock status of the SIM card in the specified slot. This API uses an asy
```js
let lockInfo = {
lockType = 1,
lockType: sim.LockType.PIN_LOCK,
password = "1234",
state = 0
state: sim.LockState.LOCK_OFF
};
sim.setLockState(0, lockInfo, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
......@@ -1135,9 +1135,9 @@ Sets the lock status of the SIM card in the specified slot. This API uses a prom
```js
let lockInfo = {
lockType = 1,
lockType: sim.LockType.PIN_LOCK,
password = "1234",
state = 0
state: sim.LockState.LOCK_OFF
};
let promise = sim.setLockState(0, lockInfo);
promise.then(data => {
......@@ -2236,12 +2236,12 @@ Adds contact numbers for the SIM card in the specified slot. This API uses an as
```js
let diallingNumbersInof = {
alphaTag = "alpha",
number = "138xxxxxxxx",
recordNumber = 123,
pin2 = "1234"
alphaTag: "alpha",
number: "138xxxxxxxx",
recordNumber: 123,
pin2: "1234"
};
sim.addIccDiallingNumbers(0, 1, diallingNumbersInof, (err, data) => {
sim.addIccDiallingNumbers(0, sim.ContactType.GENERAL_CONTACT, diallingNumbersInof, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......@@ -2277,12 +2277,12 @@ Adds contact numbers for the SIM card in the specified slot. This API uses a pro
```js
let diallingNumbersInof = {
alphaTag = "alpha",
number = "138xxxxxxxx",
recordNumber = 123,
pin2 = "1234"
alphaTag: "alpha",
number: "138xxxxxxxx",
recordNumber: 123,
pin2: "1234"
};
let promise = sim.addIccDiallingNumbers(0, 1, diallingNumbersInof);
let promise = sim.addIccDiallingNumbers(0, sim.ContactType.GENERAL_CONTACT, diallingNumbersInof);
promise.then(data => {
console.log(`addIccDiallingNumbers success, promise: data->${JSON.stringify(data)}`);
}).catch(err => {
......@@ -2315,12 +2315,12 @@ Deletes contact numbers from the SIM card in the specified slot. This API uses a
```js
let diallingNumbersInof = {
alphaTag = "alpha",
number = "138xxxxxxxx",
recordNumber = 123,
pin2 = "1234"
alphaTag: "alpha",
number: "138xxxxxxxx",
recordNumber: 123,
pin2: "1234"
};
sim.delIccDiallingNumbers(0, 1, diallingNumbersInof, (err, data) => {
sim.delIccDiallingNumbers(0, sim.ContactType.GENERAL_CONTACT, diallingNumbersInof, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......@@ -2356,12 +2356,12 @@ Deletes contact numbers from the SIM card in the specified slot. This API uses a
```js
let diallingNumbersInof = {
alphaTag = "alpha",
number = "138xxxxxxxx",
recordNumber = 123,
pin2 = "1234"
alphaTag: "alpha",
number: "138xxxxxxxx",
recordNumber: 123,
pin2: "1234"
};
let promise = sim.delIccDiallingNumbers(0, 1, diallingNumbersInof);
let promise = sim.delIccDiallingNumbers(0, sim.ContactType.GENERAL_CONTACT, diallingNumbersInof);
promise.then(data => {
console.log(`delIccDiallingNumbers success, promise: data->${JSON.stringify(data)}`);
}).catch(err => {
......@@ -2394,12 +2394,12 @@ Updates contact numbers for the SIM card in the specified slot. This API uses an
```js
let diallingNumbersInof = {
alphaTag = "alpha",
number = "138xxxxxxxx",
recordNumber = 123,
pin2 = "1234"
alphaTag: "alpha",
number: "138xxxxxxxx",
recordNumber: 123,
pin2: "1234"
};
sim.updateIccDiallingNumbers(0, 1, diallingNumbersInof, (err, data) => {
sim.updateIccDiallingNumbers(0, sim.ContactType.GENERAL_CONTACT, diallingNumbersInof, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......@@ -2435,12 +2435,12 @@ Updates contact numbers for the SIM card in the specified slot. This API uses a
```js
let diallingNumbersInof = {
alphaTag = "alpha",
number = "138xxxxxxxx",
recordNumber = 123,
pin2 = "1234"
alphaTag: "alpha",
number: "138xxxxxxxx",
recordNumber: 123,
pin2: "1234"
};
let promise = sim.updateIccDiallingNumbers(0, 1, diallingNumbersInof);
let promise = sim.updateIccDiallingNumbers(0, sim.ContactType.GENERAL_CONTACT, diallingNumbersInof);
promise.then(data => {
console.log(`updateIccDiallingNumbers success, promise: data->${JSON.stringify(data)}`);
}).catch(err => {
......@@ -2602,7 +2602,7 @@ Unlocks the SIM card in the specified slot. This API uses an asynchronous callba
```js
let persoLockInfo = {
lockType = 0,
lockType = sim.PersoLockType.PN_PIN_LOCK,
password = "1234"
};
sim.unlockSimLock(0, persoLockInfo, (err, data) => {
......@@ -2640,7 +2640,7 @@ Unlocks the SIM card in the specified slot. This API uses a promise to return th
```js
let persoLockInfo = {
lockType = 0,
lockType = sim.PersoLockType.PN_PIN_LOCK,
password = "1234"
};
let promise = sim.unlockSimLock(0, persoLockInfo);
......
......@@ -397,7 +397,7 @@ Splits an SMS message into multiple segments. This API uses an asynchronous call
**Example**
```js
string content= "long message";
let content = "long message";
sms.splitMessage(content, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
......@@ -431,7 +431,7 @@ Splits an SMS message into multiple segments. This API uses a promise to return
**Example**
```js
string content = "long message";
let content = "long message";
let promise = sms.splitMessage(content);
promise.then(data => {
console.log(`splitMessage success, promise: data->${JSON.stringify(data)}`);
......@@ -463,10 +463,10 @@ Adds a SIM message. This API uses an asynchronous callback to return the result.
```js
let simMessageOptions = {
slotId = 0,
smsc = "test",
pdu = "xxxxxx",
status = 0
slotId: 0,
smsc: "test",
pdu: "xxxxxx",
status: sms.SimMessageStatus.SIM_MESSAGE_STATUS_READ
};
sms.addSimMessage(simMessageOptions, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
......@@ -502,10 +502,10 @@ Adds a SIM message. This API uses a promise to return the result.
```js
let simMessageOptions = {
slotId = 0,
smsc = "test",
pdu = "xxxxxx",
status = 0
slotId: 0,
smsc: "test",
pdu: "xxxxxx",
status: sms.SimMessageStatus.SIM_MESSAGE_STATUS_READ
};
let promise = sms.addSimMessage(simMessageOptions);
promise.then(data => {
......@@ -607,9 +607,9 @@ Updates a SIM message. This API uses an asynchronous callback to return the resu
```js
let updateSimMessageOptions = {
slotId = 0,
msgIndex = 1,
newStatus = 0,
slotId: 0,
msgIndex: 1,
newStatus: sms.SimMessageStatus.SIM_MESSAGE_STATUS_FREE,
pdu = "xxxxxxx",
smsc = "test"
};
......@@ -647,9 +647,9 @@ Updates a SIM message. This API uses a promise to return the result.
```js
let updateSimMessageOptions = {
slotId = 0,
msgIndex = 1,
newStatus = 0,
slotId: 0,
msgIndex: 1,
newStatus: sms.SimMessageStatus.SIM_MESSAGE_STATUS_FREE,
pdu = "xxxxxxx",
smsc = "test"
};
......@@ -749,10 +749,11 @@ Sets the cell broadcast configuration. This API uses an asynchronous callback to
```js
let cbConfigOptions = {
slotId = 0,
smsc = "test",
pdu = "xxxxxxxx",
status = 0
slotId: 0,
enable: true,
startMessageId: 100,
endMessageId: 200,
ranType: sms.RanType.TYPE_GSM
};
sms.setCBConfig(cbConfigOptions, (err, data) => {
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
......@@ -788,13 +789,14 @@ Sets the cell broadcast configuration. This API uses a promise to return the res
```js
let cbConfigOptions = {
slotId = 0,
smsc = "test",
pdu = "xxxxxxxx",
status = 0
slotId: 0,
enable: true,
startMessageId: 100,
endMessageId: 200,
ranType: sms.RanType.TYPE_GSM
};
let promise = sms.setCBConfig(cbConfigOptions);
promise.then(data =>
promise.then(data => {
console.log(`setCBConfig success, promise: data->${JSON.stringify(data)}`);
}).catch(err => {
console.error(`setCBConfig failed, promise: err->${JSON.stringify(err)}`);
......@@ -859,7 +861,7 @@ Obtains SMS message segment information. This API uses a promise to return the r
```js
let slotId = 0;
let promise = sms.getSmsSegmentsInfo(slotId, "message", false);
promise.then(data =>
promise.then(data => {
console.log(`getSmsSegmentsInfo success, promise: data->${JSON.stringify(data)}`);
}).catch(err => {
console.error(`getSmsSegmentsInfo failed, promise: err->${JSON.stringify(err)}`);
......@@ -886,7 +888,7 @@ Checks whether SMS is supported on IMS. This API uses an asynchronous callback t
```js
sms.isImsSmsSupported((err, data) => {
console.log(`callback: err->${JSON.(err)}, data->${JSON.stringify(data)}`);
console.log(`callback: err->${JSON.stringify(err)}, data->${JSON.stringify(data)}`);
});
```
......@@ -1023,7 +1025,7 @@ Decodes MMS messages. This API uses a promise to return the result.
```js
let mmsFilePathName = "filename";
let promise = sms.getSmscAddr(mmsFilePathName);
let promise = sms.decodeMms(mmsFilePathName);
promise.then(data => {
console.log(`decodeMms success, promise: data->${JSON.stringify(data)}`);
}).catch(err => {
......@@ -1092,13 +1094,13 @@ Encodes MMS messages. This API uses a promise to return the result.
```js
let mmsAcknowledgeInd = {
transactionId = "100",
version = 0x10,
reportAllowed = 128
transactionId: "100",
version: sms.MmsVersionType.MMS_VERSION_1_0,
reportAllowed = sms.ReportType.MMS_YES
};
let mmsInformation = {
messageType = 133,
mmsType = mmsAcknowledgeInd
messageType: sms.MessageType.TYPE_MMS_ACKNOWLEDGE_IND,
mmsType: mmsAcknowledgeInd
};
let promise = sms.encodeMms(mmsInformation);
promise.then(data => {
......
......@@ -75,7 +75,7 @@ Obtains detailed information about a system error code.
callbackWrapper(original: Function): (err: Object, value: Object )=&gt;void
Calls back an asynchronous function. In the callback, the first parameter indicates the cause of the rejection (the value is **null** if the promise has been resolved), and the second parameter indicates the resolved value.
Wraps an asynchronous function (or a function that returns a promise) into an error-first callback, which means that **(err, value) => ...** is used as the last parameter of the callback. In the callback, the first parameter indicates the cause of the rejection (the value is **null** if the promise has been resolved), and the second parameter indicates the resolved value.
**System capability**: SystemCapability.Utils.Lang
......@@ -110,9 +110,10 @@ Calls back an asynchronous function. In the callback, the first parameter indica
promiseWrapper(original: (err: Object, value: Object) =&gt; void): Object
> **NOTE**
>
> This API is deprecated since API version 9. You are advised to use **[util.promisify9+](#utilpromisify9)** instead.
Processes an asynchronous function and returns a promise version.
Wraps a function that follows the error-first callback paradigm into a promise.
**System capability**: SystemCapability.Utils.Lang
......
......@@ -2,7 +2,7 @@
- Access Control
- [Access Control (Permission) Overview](accesstoken-overview.md)
- [Access Control (Permission) Development](accesstoken-guidelines.md)
- [Guide for Requesting Permissions from User](accesstoken-guidelines.md)
- [Application Permission List](permission-list.md)
- User Authentication
- [User Authentication Overview](userauth-overview.md)
......
# Access Control (Permission) Development
# Guide for Requesting Permissions from User
## When to Use
......@@ -13,14 +13,14 @@ In this example, the app requires the **ohos.permission.PERMISSION1** and **ohos
> In this scenario, the required permissions include a **user_grant** permission. You can check whether the caller has the required permission through permission verification.
>
> If the permission verification result indicates that the app has not obtained that permission, dynamic user authorization is required.
>
## Available APIs
The table below lists only the API used in this guide. For more information, see the [API Reference](../reference/apis/js-apis-abilityAccessCtrl.md).
The table below lists only the API used in this guide. For more information, see [Ability Access control](../reference/apis/js-apis-ability-context.md).
| API | Description |
| ------------------------------------------------------------ | --------------------------------------------------- |
| verifyAccessToken(tokenID: number, permissionName: string): Promise&lt;GrantStatus&gt; | Verifies whether an app has the specified permission. This API uses a promise to return the result.|
| requestPermissionsFromUser(permissions: Array&lt;string&gt;, requestCallback: AsyncCallback&lt;PermissionRequestResult&gt;) : void; | Requests permissions from the user by displaying a dialog box. This API uses an asynchronous callback to return the result.|
## Declaring Permissions
......@@ -137,22 +137,22 @@ If the verification result indicates that the app has the permission, the app ca
> **CAUTION**
>
> The permissions authorized by user are not permanent, because the user may revoke the authorization at any time. Therefore, even if the user has granted the requested permission to an app, the app's permission must be verified before the app calls an API protected by the permission.
> The permission authorized by a user is not permanent, because the user may revoke the authorization at any time. Each time before the API protected by the permission is called, call **requestPermissionsFromUser()** to request the permission.
## Example
The procedure is as follows:
The procedure for requesting user authorization is as follows:
1. Obtain the ability context.
2. Call **requestPermissionsFromUser** to verify whether the app has required permissions.
3. Proceed based on the permission verification result.
2. Call **requestPermissionsFromUser()** to request user authorization. The API determines whether to display a dialog box to request user authorization based on whether the app has the permission.
3. Check whether the app has the permission based on the return value. If the app has the permission, the API can be invoked.
```js
// OnWindowStageCreate lifecycle of the ability
// OnWindowStageCreate of the ability
onWindowStageCreate() {
var context = this.context
let array:Array<string> = ["ohos.permission.PERMISSION2"];
// requestPermissionsFromUser determines whether to invoke a pop-up window based on the permission authorization status.
// requestPermissionsFromUser determines whether to display a dialog box based on the permission authorization status.
context.requestPermissionsFromUser(array).then(function(data) {
console.log("data type:" + typeof(data));
console.log("data:" + data);
......@@ -165,4 +165,4 @@ The procedure is as follows:
```
> **NOTE**<br>
> For details about how to use **requestPermissionsFromUser**, see [API Reference](../reference/apis/js-apis-ability-context.md).
> For details about the APIs, see [AbilityContext](../reference/apis/js-apis-ability-context.md).
......@@ -32,7 +32,7 @@
- [Graphics](subsystems/subsys-graphics-overview.md)
- [Multimedia](subsystems/subsys-multimedia-camera-overview.md)
- [Utils](subsystems/subsys-utils-overview.md)
- [AI Framework](subsystems/subsys-aiframework-guide.md)
- [AI Framework](subsystems/subsys-ai-aiframework-devguide.md)
- [Data Management](subsystems/subsys-data-relational-database-overview.md)
- [Sensor](subsystems/subsys-sensor-overview.md)
- [USB](subsystems/subsys-usbservice-overview.md)
......
......@@ -45,6 +45,7 @@
- Peripheral Driver Usage
- [Audio](driver-peripherals-audio-des.md)
- [Camera](driver-peripherals-camera-des.md)
- [Codec](driver-peripherals-codec-des.md)
- [Facial Authentication](driver-peripherals-face_auth-des.md)
- [Fingerprint Authentication](driver-peripherals-fingerprint_auth-des.md)
- [LCD](driver-peripherals-lcd-des.md)
......
此差异已折叠。
......@@ -111,12 +111,12 @@ The WLAN module provides the following types of APIs:
| API| Description|
| -------- | -------- |
| int32_t (\*init)(struct NetDevice \*netDev) | Initializes a network device. |
| struct NetDevStats \*(\*getStats)(struct NetDevice \*netDev) | Obtains the state of a network device. |
| int32_t (\*init)(struct NetDevice \*netDev) | Initializes a network device.|
| struct NetDevStats \*(\*getStats)(struct NetDevice \*netDev) | Obtains the state of a network device.|
| int32_t (\*setMacAddr)(struct NetDevice \*netDev, void \*addr) | Sets the MAC address.|
| void (\*deInit)(struct NetDevice \*netDev) | Deinitializes a network device. |
| int32_t (\*open)(struct NetDevice \*netDev) | Opens a network device. |
| int32_t (\*stop)(struct NetDevice \*netDev) | Stops a network device. |
| void (\*deInit)(struct NetDevice \*netDev) | Deinitializes a network device.|
| int32_t (\*open)(struct NetDevice \*netDev) | Opens a network device.|
| int32_t (\*stop)(struct NetDevice \*netDev) | Stops a network device.|
- The WLAN Driver module provides APIs that you can directly use to create or release a **WifiModule**, connect to or disconnect from a WLAN hotspot, request or release a **NetBuf**, and convert between the **pbuf** structure of Lightweight IP (lwIP) and a **NetBuf**.
......@@ -439,6 +439,7 @@ The following uses the Hi3881 WLAN chip as an example to describe how to initial
}
return wal_deinit_drv_wlan_netdev(netDevice);
}
```
During the chip initialization process, call **NetDeviceInit()** to initialize a network device, call **NetDeviceAdd()** to add the network device to a protocol stack, and hook function pointers of **netdev**.
......@@ -511,12 +512,11 @@ The following uses the Hi3881 WLAN chip as an example to describe how to initial
hi_u32 ret = NetDeviceAdd(netdev, (Protocol80211IfType)type);
...
return HI_SUCCESS;
}
```
3. Bind the commands to be delivered, including setting the MAC address and transmit power, implement STA connection and scan, start APs, and setting the country code.
```c
......@@ -580,7 +580,7 @@ The following uses the Hi3881 WLAN chip as an example to describe how to initial
4. Invoke the event reporting APIs.
The WLAN framework provides the event reporting APIs. For example, call **HdfWiFiEventNewSta AP** to report information about the newly associated STA. For details, see **hdf_wifi_event.c**.
The WLAN framework provides the event reporting APIs. For details, see hdf_wifi_event.c. For example, call **HdfWiFiEventNewSta AP** to report information about the newly associated STA.
```c
hi_u32 oal_cfg80211_new_sta(oal_net_device_stru *net_device, const hi_u8 *mac_addr, hi_u8 addr_len,
......@@ -678,7 +678,7 @@ Develop test cases in the WLAN module unit test to verify the basic features of
exit 0
```
- Create a **udhcpd.conf** file (used to start the **udhcpd**) and copy the following content to the file:
- Create a **udhcpd.conf** file (used to start the **udhcpd**) and copy the following content to the file. In the following, **opt dns** *x.x.x.x* *x.x.x.x* indicates two DNS servers configured. You can configure DNS servers as required.
```text
start 192.168.12.2
......@@ -692,7 +692,7 @@ Develop test cases in the WLAN module unit test to verify the basic features of
offer_time 60 #default: 60 (1 minute)
min_lease 60 #defult: 60
lease_file /vendor/etc/udhcpd.leases
opt dns 10.221.0.11 8.8.8.8
opt dns x.x.x.x x.x.x.x
option subnet 255.255.255.0
opt router 192.168.12.1
```
......@@ -734,7 +734,7 @@ Develop test cases in the WLAN module unit test to verify the basic features of
4. On the mobile phone, select the network named **test** in the available Wi-Fi list and enter the password.
The network name and password are configured in the **hostapd.conf** file. You can see the network name in the connected Wi-Fi list if the connection is successful.
The network name and password are configured in the **hostapd.conf** file. You can see that network name in the connected Wi-Fi list if the connection is successful.
5. Ping the test terminal from the development board.
......@@ -742,7 +742,7 @@ Develop test cases in the WLAN module unit test to verify the basic features of
busybox ping xxx.xxx.xxx.xxx
```
In the command, xxx.xxx.xxx.xxx indicates the IP address of the test terminal. If the test terminal can be pinged, the basic features of the WLAN driver are implemented successfully.
In the command, xxx.xxx.xxx.xxx indicates the IP address of the test terminal. If the test terminal can be pinged, the WLAN driver provides basic features normally.
- Verify basic STA features.
......@@ -771,7 +771,7 @@ Develop test cases in the WLAN module unit test to verify the basic features of
busybox ping xxx.xxx.xxx.xxx
```
In the command, xxx.xxx.xxx.xxx indicates the IP address of the test terminal. If the test terminal can be pinged, the basic features of the WLAN driver are implemented successfully.
In the command, xxx.xxx.xxx.xxx indicates the IP address of the test terminal. If the test terminal can be pinged, the WLAN driver provides basic features normally.
3. Verify the unit test cases.
......@@ -872,6 +872,8 @@ Develop test cases in the WLAN module unit test to verify the basic features of
#define MAC_LEN 6
#define HDF_SUCCESS 0
#define HDF_FAILURE (-1)
```
static int32_t hal_main()
{
......@@ -924,8 +926,6 @@ Develop test cases in the WLAN module unit test to verify the basic features of
}
```
4. Verify the test cases.
1. Push the test cases to the development board.
......@@ -944,8 +944,12 @@ Develop test cases in the WLAN module unit test to verify the basic features of
./ Test case name.
```
3. Check the test case execution result.
## Reference
- Code repositories:
......@@ -974,7 +978,9 @@ Develop test cases in the WLAN module unit test to verify the basic features of
**//drivers/hdf_core/framework/model/network/wifi**
- External APIs of the WLAN module:**//drivers/hdf_core/framework/include/wifi**
- External APIs of the WLAN module:
**//drivers/hdf_core/framework/include/wifi**
- HDF network model APIs:
......
......@@ -274,7 +274,7 @@ int32_t I3cTestRequestIbi(void)
}
ret = I3cRequestIbi(i3cHandle, 0x3F, TestI3cIbiFunc, 16);
if (ret != 0) {
HDF_LOGE("%s: Requset IBI failed!", __func__);
HDF_LOGE("%s: Request IBI failed!", __func__);
return -1;
}
......
......@@ -25,10 +25,10 @@ struct MmcCntlrOps {
int32_t (*setSdioIrq)(struct MmcCntlr *cntlr, bool enable);
int32_t (*hardwareReset)(struct MmcCntlr *cntlr);
int32_t (*systemInit)(struct MmcCntlr *cntlr);
int32_t (*setEnhanceSrobe)(struct MmcCntlr *cntlr, bool enable);
int32_t (*setEnhanceStrobe)(struct MmcCntlr *cntlr, bool enable);
int32_t (*switchVoltage)(struct MmcCntlr *cntlr, enum MmcVolt volt);
bool (*devReadOnly)(struct MmcCntlr *cntlr);
bool (*devPluged)(struct MmcCntlr *cntlr);
bool (*devPlugged)(struct MmcCntlr *cntlr);
bool (*devBusy)(struct MmcCntlr *cntlr);
int32_t (*tune)(struct MmcCntlr *cntlr, uint32_t cmdCode);
int32_t (*rescanSdioDev)(struct MmcCntlr *cntlr);
......@@ -47,10 +47,10 @@ struct MmcCntlrOps {
| setSdioIrq | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**enable**: whether to enable Secure Digital Input Output (SDIO) interrupts.| HDF_STATUS| Enables or disables SDIO interrupts.|
| hardwareReset | **cntlr**: structure pointer to the MMC controller at the core layer.| HDF_STATUS| Resets hardware.|
| systemInit | **cntlr**: structure pointer to the MMC controller at the core layer.| HDF_STATUS| Performs system initialization.|
| setEnhanceSrobe | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**enable**: whether to enable the enhanced strobe feature.| HDF_STATUS| Sets the enhanced strobe feature.|
| setEnhanceStrobe | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**enable**: whether to enable the enhanced strobe feature.| HDF_STATUS| Sets the enhanced strobe feature.|
| switchVoltage | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**volt**: voltage to set, which can be 3.3 V, 1.8 V, or 1.2 V.| HDF_STATUS| Sets the voltage.|
| devReadOnly | **cntlr**: structure pointer to the MMC controller at the core layer.| Boolean value| Checks whether the device is read-only.|
| cardPluged | **cntlr**: structure pointer to the MMC controller at the core layer.| Boolean value| Checks whether the device is removed.|
| cardPlugged | **cntlr**: structure pointer to the MMC controller at the core layer.| Boolean value| Checks whether the device is removed.|
| devBusy | **cntlr**: structure pointer to the MMC controller at the core layer.| Boolean value| Checks whether the device is being used.|
| tune | **cntlr**: structure pointer to the MMC controller at the core layer.<br>**cmdCode**: command code of the uint32_t type.| HDF_STATUS| Tunes the oscillator circuit frequency.|
| rescanSdioDev | **cntlr**: structure pointer to the MMC controller at the core layer.| HDF_STATUS| Scans and adds an SDIO device.|
......@@ -254,7 +254,7 @@ The following uses **himci.c** as an example to present the information required
uint32_t maxBlkNum;
uint32_t maxBlkSize;
uint32_t maxReqSize;
bool devPluged;
bool devPlugged;
bool detecting;
void *priv;
};
......@@ -273,10 +273,10 @@ The following uses **himci.c** as an example to present the information required
.setSdioIrq = HimciSetSdioIrq,
.hardwareReset = HimciHardwareReset,
.systemInit = HimciSystemInit,
.setEnhanceSrobe= HimciSetEnhanceSrobe,
.setEnhanceStrobe= HimciSetEnhanceStrobe,
.switchVoltage = HimciSwitchVoltage,
.devReadOnly = HimciDevReadOnly,
.devPluged = HimciCardPluged,
.devPlugged = HimciCardPlugged,
.devBusy = HimciDevBusy,
.tune = HimciTune,
.rescanSdioDev = HimciRescanSdioDev,
......
......@@ -39,21 +39,7 @@
- [Utils Overview](subsys-utils-overview.md)
- [Utils Development](subsys-utils-guide.md)
- [Utils FAQ](subsys-utils-faqs.md)
- AI Framework
- [AI Engine Framework](subsys-aiframework-guide.md)
- [Development Environment](subsys-aiframework-envbuild.md)
- Technical Specifications
- [Code Management](subsys-aiframework-tech-codemanage.md)
- [Naming](subsys-aiframework-tech-name.md)
- [API Development](subsys-aiframework-tech-interface.md)
- Development Guidelines
- [SDK](subsys-aiframework-devguide-sdk.md)
- [Plug-in](subsys-aiframework-devguide-plugin.md)
- [Configuration File](subsys-aiframework-devguide-conf.md)
- Development Examples
- [KWS SDK](subsys-aiframework-demo-sdk.md)
- [KWS Plug-in](subsys-aiframework-demo-plugin.md)
- [KWS Configuration File](subsys-aiframework-demo-conf.md)
- [AI Framework](subsys-ai-aiframework-devguide.md)
- Data Management
- RDB
- [RDB Overview](subsys-data-relational-database-overview.md)
......@@ -103,9 +89,10 @@
- [DFX Overview](subsys-dfx-overview.md)
- [HiLog Development](subsys-dfx-hilog-rich.md)
- [HiLog\_Lite Development](subsys-dfx-hilog-lite.md)
- [HiTrace Development](subsys-dfx-hitrace.md)
- [HiTraceChain Development](subsys-dfx-hitracechain.md)
- [HiCollie Development](subsys-dfx-hicollie.md)
- HiSysEvent Development
- [HiSysEvent Overview](subsys-dfx-hisysevent-overview.md)
- [HiSysEvent Logging Configuration](subsys-dfx-hisysevent-logging-config.md)
- [HiSysEvent Logging](subsys-dfx-hisysevent-logging.md)
- [HiSysEvent Listening](subsys-dfx-hisysevent-listening.md)
......
# KWS Configuration File<a name="EN-US_TOPIC_0000001121062971"></a>
1. Add the KWS configuration file to the **//foundation/ai/engine/services/common/protocol/plugin\_config/plugin\_config\_ini/** directory.
```
[base]
supported_boards = hi3516dv300
related_sessions = asr_keyword_spotting+20001002
// Naming rule: [algorithm name+algorithm version], for example, [asr_keyword_spotting+20001002]
[asr_keyword_spotting+20001002]
AID = asr_keyword_spotting
VersionCode = 20001002
VersionName = 2.00.01.002
XPU = NNIE
District = China
// Location of the complied .so file of the plug-in
FullPath = /usr/lib/libasr_keyword_spotting.so
Chipset = ALL
ChkSum = ''
Key = ''
```
2. Add the type ID of the KWS algorithm to the **aie\_algorithm\_type.h** file in the **//foundation/ai/engine/services/common/protocol/plugin\_config/** directory.
```
// Make sure that the type ID maps to the sequence number in ALGORITHM_TYPE_ID_LITS.
const int ALGORITHM_TYPE_KWS = 3;
```
3. Add the name of the KWS algorithm and its sequence number in **ALGORITHM\_TYPE\_ID\_LITS** to the **aie\_plugin\_info.h** file in the **//foundation/ai/engine/services/server/plugin\_manager/include/** directory.
```
const std::string ALGORITHM_ID_SAMPLE_1 = "sample_plugin_1";
const std::string ALGORITHM_ID_SAMPLE_2 = "sample_plugin_2";
const std::string ALGORITHM_ID_IVP = "cv_human_detect";
// Add the name of the KWS algorithm: asr_keyword_spotting.
// Name the algorithm variable in the same way as the algorithm type ID in ALGORITHM_TYPE_ID_LIST, for example, ALGORITHM_ID_KWS.
const std::string ALGORITHM_ID_KWS = "asr_keyword_spotting";
const std::string ALGORITHM_ID_IC = "cv_image_classification";
const std::string ALGORITHM_ID_INVALID = "invalid algorithm id";
const std::vector<std::string> ALGORITHM_TYPE_ID_LIST = {
ALGORITHM_ID_SAMPLE_1,
ALGORITHM_ID_SAMPLE_2,
ALGORITHM_ID_IVP,
// Add the sequence number of the KWS algorithm to ALGORITHM_TYPE_ID_LITS, so that the name of the KWS algorithm can be obtained based on the sequence number.
// Make sure that the algorithm name maps to the sequence number in ALGORITHM_TYPE_ID_LITS.
ALGORITHM_ID_KWS,
ALGORITHM_ID_IC,
};
```
# KWS Plug-in<a name="EN-US_TOPIC_0000001090714913"></a>
1. Add the API of the KWS plug-in to the **//foundation/ai/engine/services/server/plugin** directory. This API is used to call AI capabilities. The following code snippet is an example API implementation of the KWS plug-in. The reference code is available at the **//foundation/ai/engine/services/server/plugin/asr/keyword\_spotting** directory.
```
#include "plugin/i_plugin.h
class KWSPlugin : public IPlugin {
public:
KWSPlugin();
~KWSPlugin();
const long long GetVersion() const override;
const char* GetName() const override;
const char* GetInferMode() const override;
int32_t Prepare(long long transactionId, const DataInfo &amp;amp;inputInfo, DataInfo &amp;amp;outputInfo) override;
int32_t SetOption(int optionType, const DataInfo &amp;amp;inputInfo) override;
int32_t GetOption(int optionType, const DataInfo &amp;amp;inputInfo, DataInfo &amp;amp;outputInfo) override;
int32_t SyncProcess(IRequest *request, IResponse *&amp;amp;response) override;
int32_t AsyncProcess(IRequest *request, IPluginCallback*callback) override;
int32_t Release(bool isFullUnload, long long transactionId, const DataInfo &amp;amp;inputInfo) override;
};
```
The preceding code implements the **IPlugin** API provided by the server. The following table shows the mapping between the client APIs and the plug-in APIs.
**Table 1** Mapping between the client APIs and the plug-in APIs
| Client API | Plug-in API | Description |
| ---------- | ----------- | ----------- |
| AieClientPrepare | Prepare | Initializes the inference algorithm plug-in. For KWS, this API loads the KWS model from the fixed location (/sdcard/wenwen_inst.wk) to the memory. |
| AieClientSyncProcess | SyncProcess | Executes the inference algorithm synchronously. For KWS, this API synchronously executes the audio inference algorithm to determine whether the specified wakeup keyword exists in the audio. |
| AieClientAsyncProcess | AsyncProcess | Executes the inference algorithm asynchronously. Currently, this API is not used in KWS. However, you can implement the API based on your use case. |
| AieClientSetOption | SetOption | Sets algorithm-related configuration items, such as the confidence threshold and delay. Currently, this API is not used in KWS. However, you can implement the API based on your use case. |
| AieClientGetOption | GetOption | Obtains algorithm-related configuration items. For KWS, this API can obtain the input and output scale of the KWS model. The input scale is the MFCC feature (fixed value: 4000) required by the KWS model, and the output scale is the confidence (fixed value: 2) of the result. |
| AieClientRelease | Release | Releases the algorithm model. For KWS, this API releases the specified algorithm model and clears the dynamic memory in the feature processor. |
>![](../public_sys-resources/icon-note.gif)**NOTE**
>- The **AieClientInit** and **AieClientDestroy** APIs are used to connect to and disconnect from the server, respectively. They are not called in the plug-in algorithm and therefore do not need to be defined in the plug-in.
>- The KWS plug-in needs to use the **PLUGIN\_INTERFACE\_IMPL** statement to expose the function pointer. Otherwise, the plug-in cannot be properly loaded.
```
PLUGIN_INTERFACE_IMPL(KWSPlugin);
```
\ No newline at end of file
# KWS SDK<a name="EN-US_TOPIC_0000001090776709"></a>
1. Add the API of the KWS SDK to the **//foundation/ai/engine /interfaces/kits** directory. This API can be called by third-party applications. The following code snippet is an example API for the KWS SDK. The reference code is available at the **//foundation/ai/engine /interfaces/kits/asr/keyword\_spotting** directory.
```
class KWSSdk {
public:
KWSSdk();
virtual ~KWSSdk();
// Create a KWS SDK instance.
int32_t Create();
// Synchronously execute the KWS task.
int32_t SyncExecute(const Array<int16_t> &audioInput);
// Set the KWS callback.
int32_t SetCallback(const std::shared_ptr<KWSCallback> &callback);
// Destroy the KWS SDK instance to release the session engaged with the plug-in.
int32_t Destroy();
};
```
2. Add the API implementation of the SDK to the **//foundation/ai/engine/services/client/algorithm\_sdk** directory and call the APIs provided by the client to use the algorithm plug-in capabilities. The following code snippet is an example implementation of the **create** method in the API of the KWS SDK. For more details, see the reference code at **//foundation/ai/engine/services/client/algorithm\_sdk/asr/keyword\_spotting**.
```
int32_t KWSSdk::KWSSdkImpl::Create()
{
if (kwsHandle_ != INVALID_KWS_HANDLE) {
HILOGE("[KWSSdkImpl]The SDK has been created");
return KWS_RETCODE_FAILURE;
}
if (InitComponents() != RETCODE_SUCCESS) {
HILOGE("[KWSSdkImpl]Fail to init sdk components");
return KWS_RETCODE_FAILURE;
}
// Call the AieClientInit API provided by the client to initialize the engine service and activate IPC call.
int32_t retCode = AieClientInit(configInfo_, clientInfo_, algorithmInfo_, nullptr);
if (retCode != RETCODE_SUCCESS) {
HILOGE("[KWSSdkImpl]AieClientInit failed. Error code[%d]", retCode);
return KWS_RETCODE_FAILURE;
}
if (clientInfo_.clientId == INVALID_CLIENT_ID) {
HILOGE("[KWSSdkImpl]Fail to allocate client id");
return KWS_RETCODE_FAILURE;
}
DataInfo inputInfo = {
.data = nullptr,
.length = 0,
};
DataInfo outputInfo = {
.data = nullptr,
.length = 0,
};
// Call the AieClientPrepare API provided by the client to load the algorithm plug-in.
retCode = AieClientPrepare(clientInfo_, algorithmInfo_, inputInfo, outputInfo, nullptr);
if (retCode != RETCODE_SUCCESS) {
HILOGE("[KWSSdkImpl]AieclientPrepare failed. Error code[%d]", retCode);
return KWS_RETCODE_FAILURE;
}
if (outputInfo.data == nullptr || outputInfo.length <= 0) {
HILOGE("[KWSSdkImpl]The data or length of output info is invalid");
return KWS_RETCODE_FAILURE;
}
MallocPointerGuard<unsigned char> pointerGuard(outputInfo.data);
retCode = PluginHelper::UnSerializeHandle(outputInfo, kwsHandle_);
if (retCode != RETCODE_SUCCESS) {
HILOGE("[KWSSdkImpl]Get handle from inputInfo failed");
return KWS_RETCODE_FAILURE;
}
return KWS_RETCODE_SUCCESS;
}
```
The preceding code is the specific API implementation. The **create** function in the API of the KWS SDK calls the open **AieClientInit** and **AieClientPrepare** APIs provided by the client to connect to the server and load the algorithm model. For details, see the implementation of the **create** method in following sections.
>![](../public_sys-resources/icon-note.gif) **NOTE**
>
>The sequence for the SDK to call client APIs: **AieClientInit** -\> **AieClientPrepare** -\> **AieClientSyncProcess** or **AieClientAsyncProcess** -\> **AieClientRelease** -\> **AieClientDestroy**. An exception will be thrown if the call sequence is violated.
# Development Examples<a name="EN-US_TOPIC_0000001077767514"></a>
For your better understanding, a KWS application is used as an example to walk you through the development process. You can develop the KWS SDK and plug-in based on the AI engine framework on the Hi3516D V300 development board, compile an image for the new version, and burn the image into the version. Then, develop an application with the KWS function. The application can receive external audio and pass the audio to the SDK API. If the audio contains specified keywords, the application will be able to recognize these keywords and print them in the command line.
This example uses a fixed keyword **Hi, xiaowen** for illustration. If the input audio contains **Hi, xiaowen**, the application prints **\[Hi, xiaowen\]**; otherwise, the application prints **\[UNKNOWN\]**.
- **[KWS SDK](subsys-aiframework-demo-sdk.md)**
- **[KWS Plug-in](subsys-aiframework-demo-plugin.md)**
- **[KWS Configuration File](subsys-aiframework-demo-conf.md)**
# Configuration File<a name="EN-US_TOPIC_0000001120666799"></a>
The SDK identifies the plug-in type based on **algorithmVersion** and **algorithmType** in the **AlgorithmInfo** structure so it can call the plug-in capabilities. Therefore, you need to develop the plug-in configuration file as follows:
1. Add the plug-in configuration file to the **//foundation/ai/engine/services/common/protocol/plugin\_config/plugin\_config\_ini/** directory.
2. Add the algorithm type to the **aie\_algorithm\_type.h** file in the **//foundation/ai/engine/services/common/protocol/plugin\_config/** directory.
3. Add the name of the KWS algorithm and its sequence number in **ALGORITHM\_TYPE\_ID\_LITS** to the **aie\_plugin\_info.h** file in the **//foundation/ai/engine/services/server/plugin\_manager/include/** directory.
For details about the development process, see the development example for the KWS configuration file.
# Development Guidelines<a name="EN-US_TOPIC_0000001090475723"></a>
To access the AI engine framework, you need to develop the SDKs and plug-ins shown in [Figure 1](subsys-aiframework-guide.md#fig143186187187). In this way, you can call the APIs provided by the SDKs to call the algorithm capabilities of plug-ins to implement lifecycle management and on-demand deployment of AI capabilities.
- **[SDK](subsys-aiframework-devguide-sdk.md)**
- **[Plug-in](subsys-aiframework-devguide-plugin.md)**
- **[Configuration File](subsys-aiframework-devguide-conf.md)**
# Development Environment<a name="EN-US_TOPIC_0000001077607540"></a>
1. Prepare development boards Hi3516D V300 and Hi3518E V300.
2. [Download the source code](../get-code/sourcecode-acquire.md).
# AI Engine Framework<a name="EN-US_TOPIC_0000001077309802"></a>
The AI subsystem of OpenHarmony provides native distributed AI capabilities. At the heart of the subsystem is a unified AI engine framework, which implements quick integration of AI algorithm plug-ins. The framework consists of the plug-in management, module management, and communication management modules, fulfilling lifecycle management and on-demand deployment of AI algorithms. Plug-in management implements lifecycle management, on-demand deployment, and quick integration of AI algorithm plug-ins. Module management implements task scheduling and client instance management. Communication management implements inter-process communication \(IPC\) between the client and server and data transmission between the AI engine and plug-ins. Under this framework, AI algorithm APIs will be standardized to facilitate distributed calling of AI capabilities. In addition, unified inference APIs will be provided to adapt to different inference framework hierarchies. [Figure 1](#fig143186187187) shows the AI engine framework.
**Figure 1** AI engine framework<a name="fig143186187187"></a>
![](figure/en-us_image_0000001077727032.png)
# Code Management<a name="EN-US_TOPIC_0000001096216399"></a>
Code of the AI engine framework consists of three parts: **client**, **server**, and **common**. The client module provides the server connection management function. The northbound SDK needs to encapsulate and call the public APIs provided by the client in the algorithm's external APIs. The server module provides functions such as plug-in loading and task management. Plug-ins are integrated using the plug-in APIs provided by the server. The common module provides platform-related operation methods, engine protocols, and tool classes for other modules.
[Figure 1](#fig171811112818) shows the code dependency between modules of the AI engine framework.
**Figure 1** Code dependency<a name="fig171811112818"></a>
![](figure/code-dependency-(2).jpg)
## Recommendation: Develop plug-ins and northbound SDKs in the directories specified by the AI engine.<a name="section17176374131"></a>
In the overall planning of the AI engine framework, northbound SDKs are a part of the client, and plug-ins are called by the server and are considered a part of the server. Therefore, the following directories have been planned for plug-in and northbound SDK development in the AI engine framework:
- SDK code directory: //foundation/ai/engine/services/client/algorithm\_sdk
Examples:
//foundation/ai/engine/services/client/algorithm\_sdk/cv
//foundation/ai/engine/services/client/algorithm\_sdk/nlu
- Plug-in code directory: //foundation/ai/engine/services/server/plugin
Examples:
//foundation/ai/engine/services/server/plugin/cv
//foundation/ai/engine/services/server/plugin/nlu
## Rule: Store all external APIs provided by plug-ins in the **interfaces/kits** directory of the AI subsystem.<a name="section2551029111312"></a>
The AI subsystem exposes its capabilities through external APIs of northbound SDKs. According to API management requirements of OpenHarmony, store all external APIs of northbound SDKs in the **interfaces/kits** directory of the subsystem. Currently, the external APIs of plug-ins of the AI subsystem are stored in the following directory: **//foundation/ai/engine/interface/kits**. You can add a sub-directory for each newly added plug-in in this directory. For example, if you add a CV plug-in, then store its external APIs in the **//foundation/ai/engine/interfaces/kits/cv** directory.
## Rule: Make sure that plug-in compilation results are stored in the **/usr/lib** directory.<a name="section97021558121310"></a>
Plug-in loading on the server uses the dlopen mode and can only be performed in the **/usr/lib** directory. Therefore, when compiling the **.so** file of a plug-in, set the output directory as **/usr/lib** in the compilation configuration file.
# API Development<a name="EN-US_TOPIC_0000001096100171"></a>
## Rule: Encapsulate the external APIs provided by the client based on the algorithm call sequence. For the SDK of an asynchronous plug-in, implement the **IClientCb** callback API provided by the client.<a name="section15872017171616"></a>
The external APIs provided by the client of the AI engine include **AieClientInit**, **AieClientPrepare**, **AieClientSyncProcess**, **AieClientAsyncProcess**, **AieClientRelease**, **AieClientDestroy**, **AieClientSetOption**, and **AieClientGetOption**. The SDK needs to encapsulate at least the following five APIs in sequence: **AieClientInit**, **AieClientPrepare**, **AieClientSyncProcess** \(or **AieClientAsyncProcess**\), **AieClientRelease**, and **AieClientDestroy**. Otherwise, a call failure or memory leakage may occur. For example, if the **AieClientprepare** API is omitted during encapsulation, the server cannot load the plug-in. As a result, APIs that follow it cannot be called.
For an asynchronous plug-in, the SDK needs to implement the **IClientCb** API to receive the algorithm inference result from the client and return the result to the third-party caller.
## Rule: Save all common data related to client interaction in the SDK during API implementation.<a name="section011283741612"></a>
The client of the AI engine uses the singleton pattern for API implementation. If the client is connecting to multiple SDKs, each SDK needs to store all common data exchanged with the client so that they can connect to the server to perform operations such as task inference and return the result. Common data usually includes **clientInfo**, **algorithmInfo**, and **configInfo**, which are defined in the SDK's member variables.
## Recommendation: Enable the SDK to implement the **IServiceDeadCb** API defined by the client.<a name="section1199125331613"></a>
The processes running on the server are system resident processes. The server provides services for clients by way of system capabilities. The **IServiceDeadCb** API is called if a server process is abnormally killed. The SDK can implement related operations in this API, for example, stopping process call or restarting the server.
The following is an example of **IServiceDeadCb** API implementation:
```
class ServiceDeadCb : public IServiceDeadCb {
public:
ServiceDeadCb() = default;
~ServiceDeadCb() override = default;
void OnServiceDead() override
{
printf("[ServiceDeadCb]OnServiceDead Callback happens");
}
};
```
As shown above, the SDK can implement its own operations in the **OnServiceDead\(\)** function, for example, stopping API call.
## Rule: Convert dedicated algorithm data into common data of the AI engine if the SDK and plug-ins need to use the codec module.<a name="section93139389171"></a>
For plug-ins, inference data is transmitted by the third-party caller to them through the client and server. The required data type varies according to algorithms. For example, the CV algorithm requires image data, and the ASR algorithm requires audio data. To address this issue, the AI engine provides the codec capabilities to convert different types of data into common data that can be used by it.
The encoded data is as follows:
```
struct DataInfo {
unsigned char *data;
int length;
} DataInfo;
```
As shown above, **DataInfo** consists of two variables: a pointer to the data memory, and the data length.
To use the APIs of the AI engine framework, you need to:
1. Add the dependency header file **utils/encdec/include/encdec.h**.
2. Add the dependency items in the **build.gn** file.
Add **"//foundation/ai/engine/services/common"** to **include\_dirs**.
Add **"//foundation/ai/engine/services/common/utils/encdec:encdec"** to **deps**.
3. Convert different types of data through codec. The following is an example:
```
// Example function for encoding: arg1, arg2, and arg3 are variables to be encoded, and dataInfo is the encoding result.
retCode = ProcessEncode(dataInfo, arg1, arg2, arg3) // The number of parameters can be flexible.
// Example function for decoding: dataInfo is the data to be decoded, and arg1, arg2, and arg3 are the decoding result.
retCode = ProcessDecode(dataInfo, arg1, arg2, arg3) // The number of parameters can be flexible.
```
Note:
- The sequence of parameters must be the same during encoding and decoding.
- After encoding, the memory used by **dataInfo** needs to be manually released by the caller.
- The memory is managed and released separately on the server and the client.
- If a pointer contains the shared memory, no extra processing is required.
- If other types of pointers are used, you need to dereference them before using **ProcessEncode** or **ProcessDecode**.
- The codec module has not been adapted to the **class** data type and therefore it is not recommended.
## Rule: Release the memory used by the encoded or decoded parameters in the SDK. Otherwise, a memory leakage occurs.<a name="section1698441814183"></a>
Encoding is essentially a process of encapsulating different types of data in the same memory space and then encapsulating the start address and length of the memory into the body. The plug-in is unable to release the memory that has been allocated to output parameter data returned to the SDK through encoding. To obtain the data, the SDK first needs to release the memory.
The following is an example of releasing the memory:
```
DataInfo outputInfo = {
.data = nullptr,
.length = 0,
};
AieClientPrepare(clientInfo_, algorithmInfo_, inputInfo, outputInfo, nullptr);
if (outputInfo.data != nullptr) {
free(outputInfo.data);
outputInfo.data = nullptr;
outputInfo.length = 0;
}
```
## Rule: Enable plug-ins to implement the **IPlugin** API defined by the server and use the **PLUGIN\_INTERFACE\_IMPL** statement to provide the function pointer for external systems.<a name="section20850717196"></a>
The server manages a variety of plug-ins, and the API implementation logic varies according to plug-ins. To unify the plug-in loading process, the AI engine provides the **IPlugin** API. In the runtime environment, a plug-in is loaded as a dynamic link library \(DLL\) by the AI engine framework in dlopen mode. Therefore, the plug-in needs to use the **PLUGIN\_INTERFACE\_IMPL** statement to expose the function pointer. Otherwise, the plug-in cannot be properly loaded.
## Rule: Use the unified data channel provided by the AI engine for plug-ins.<a name="section1493821732019"></a>
The AI engine provides a unified data channel between the server and plug-ins to send inference requests from the SDK and returned results from plug-ins. Plug-ins need to obtain the request data and encapsulate the inference result over the data channel when calling the inference API.
The following is an example of using the data channel:
```
int SyncProcess(IRequest *request, IResponse *&response)
{
HILOGI("[IvpPlugin]Begin SyncProcess");
if (request == nullptr) {
HILOGE("[IvpPlugin]SyncProcess request is nullptr");
return RETCODE_NULL_PARAM;
}
DataInfo inputInfo = request->GetMsg();
if (inputInfo.data == nullptr) {
HILOGE("[IvpPlugin]InputInfo data is nullptr");
return RETCODE_NULL_PARAM;
}
...
response = IResponse::Create(request);
response->SetResult(outputInfo);
return RETCODE_SUCCESS;
}
```
In the example, the request and response are the data body sent over the data channel. The server encapsulates data in the request and sends it to the plug-in. After completing algorithm processing, the plug-in encapsulates the result into the response and returns it to the server over the data channel.
# Naming<a name="EN-US_TOPIC_0000001095816835"></a>
## Rule: Name an SDK in the format of **domain\_keyword<\_other information 1\_other information 2\_...\>\_sdk.so**.<a name="section62071110121516"></a>
You are advised to use the commonly known abbreviations for domains. For example, use **cv** for image and video, **asr** for voice recognition, and **translation** for text translation. Add one if there is no available abbreviation for a domain. Use keywords that accurately describe the algorithm capability of the plug-in. For example, use **keyword\_spotting** for wakeup keyword spotting \(KWS\). Add other information, such as the supported chip type and applicable region, between **keyword** and **sdk**, with each of them separated by an underscore \(\_\). Note that the name of a northbound SDK must end with **sdk**.
For example, if the SDK for the KWS plug-in supports only the Kirin 9000 chipset and is applicable only in China, then name the SDK as follows: **asr\_keyword\_spotting\_kirin9000\_china\_sdk.so**.
## Rule: Name a plug-in in the format of **domain\_keyword<\_other information 1\_other information 2\_...\>.so**.<a name="section1665562841519"></a>
Use the same naming rules as the SDK.
A plug-in maps to an SDK. Therefore, they have the same requirements for the domain, keyword, and other information in their names. The only difference is that the name of the SDK ends with **\_sdk** additionally. For example, if the plug-in is named **asr\_keyword\_spotting.so**, the corresponding northbound SDK is named **asr\_keyword\_spotting\_sdk.so**.
For example, if the SDK for the KWS plug-in supports only the Kirin 9000 chipset and is applicable only in China, then name the plug-in as follows: **asr\_keyword\_spotting\_kirin9000\_china.so**.
# Technical Specifications<a name="EN-US_TOPIC_0000001095956459"></a>
**Conventions**
**Rule**: a convention that must be observed
**Recommendation**: a convention that should be considered
- **[Code Management](subsys-aiframework-tech-codemanage.md)**
- **[Naming](subsys-aiframework-tech-name.md)**
- **[API Development](subsys-aiframework-tech-interface.md)**
# AI Framework<a name="EN-US_TOPIC_0000001157479361"></a>
- **[AI Engine Framework](subsys-aiframework-guide.md)**
- **[Development Environment](subsys-aiframework-envbuild.md)**
- **[Technical Specifications](subsys-aiframework-tech.md)**
- **[Development Guidelines](subsys-aiframework-devguide.md)**
- **[Development Examples](subsys-aiframework-demo.md)**
......@@ -7,15 +7,15 @@ HiSysEvent provides event logging APIs for OpenHarmony to record important infor
The key modules of HiSysEvent are described as follows:
- Event configuration: enables you to define HiSysEvent events in YAML files.
- [HiSysEvent logging configuration](subsys-dfx-hisysevent-logging-config.md): enables you to define HiSysEvent events in YAML files.
- Trace point configuration: provides trace point APIs and supports flushing of HiSysEvent events to disks.
- [HiSysEvent logging](subsys-dfx-hisysevent-logging.md): provides trace point APIs and supports flushing of HiSysEvent events to disks.
- Event subscription: provides APIs for you to subscribe to HiSysEvent events by event domain and event name.
- [HiSysEvent listening](subsys-dfx-hisysevent-listening.md): provides APIs for you to subscribe to HiSysEvent events by event domain and event name.
- Event query: provides APIs for you to query HiSysEvent events by event domain and event name.
- [HiSysEvent query](subsys-dfx-hisysevent-query.md): provides APIs for you to query HiSysEvent events by event domain and event name.
- Event debugging tool: allows you to subscribe to real-time HiSysEvent events and query historical HiSysEvent events.
- [HiSysEvent tool](subsys-dfx-hisysevent-tool.md): allows you to subscribe to real-time HiSysEvent events and query historical HiSysEvent events.
## Reference
......
......@@ -6,7 +6,7 @@ The DFX subsystem provides the following functions:
- HiLog: implements the logging function. It is applicable to mini-system devices \(reference memory ≥ 128 KiB\), small-system devices \(reference memory ≥ 1 MiB\), and standard-system devices \(reference memory ≥ 128 MB\).
- HiTrace: implements distributed call chain tracing. It is applicable to standard-system devices \(reference memory ≥ 128 MiB\).
- HiTraceChain: implements distributed call chain tracing. It is applicable to standard-system devices \(reference memory ≥ 128 MiB\).
- HiCollie: implements thread suspension detection. It is applicable to standard-system devices \(reference memory ≥ 128 MiB\).
- HiSysEvent: implements system event logging. It is applicable to standard-system devices \(reference memory ≥ 128 MiB\).
- HiChecker: implements defect scanning. It is applicable to standard-system devices \(reference memory ≥ 128 MiB\).
......@@ -35,3 +35,4 @@ Event logging means to collect and log events reported during system running. Th
**System event**
A system event is an indication of the system status at a given time point during system running. You can use these events to analyze the status change of the system.
<!--no_check-->
......@@ -8,7 +8,7 @@
OpenHarmony文档的著作权由OpenHarmony项目拥有。
OpenHarmony文档根据知识共享署名4.0 (Creative Commons Attribution 4.0,简称CC BY 4.0)国际公共许可协议进行版权许可。为了方便用户理解,您可以通过访问https://creativecommons.org/licenses/by/4.0/了解CC BY 4.0的概要。CC BY 4.0的完整协议内容您可以访问如下网址获取:https://creativecommons.org/licenses/by/4.0/legalcode
OpenHarmony文档根据知识共享署名4.0 (Creative Commons Attribution 4.0,简称CC BY 4.0)国际公共许可协议进行版权许可。为了方便用户理解,您可以通过访问https://creativecommons.org/licenses/by/4.0/ 了解CC BY 4.0的概要。CC BY 4.0的完整协议内容您可以访问如下网址获取:https://creativecommons.org/licenses/by/4.0/legalcode
......
......@@ -156,7 +156,7 @@ OpenHarmony支持如下几种系统类型:
## 快速入门
- [设备开发快速入门](device-dev/quick-start/quickstart-ide-lite-overview.md)
- [设备开发快速入门](device-dev/quick-start/quickstart-overview.md)
- [应用开发快速入门](application-dev/quick-start/start-overview.md)
......
......@@ -433,7 +433,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 +455,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 +472,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);
......@@ -595,7 +595,7 @@ export default class IdlTestServiceProxy implements IIdlTestService {
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) {
if (result.errCode == 0) {
let _errCode = result.reply.readInt();
if (_errCode != 0) {
let _returnValue = undefined;
......@@ -605,7 +605,7 @@ export default class IdlTestServiceProxy implements IIdlTestService {
let _returnValue = result.reply.readInt();
callback(_errCode, _returnValue);
} else {
console.log("sendRequest failed, errCode: " + result.errCode);
console.log('sendRequest failed, errCode: ' + result.errCode);
}
})
}
......@@ -617,11 +617,11 @@ export default class IdlTestServiceProxy implements IIdlTestService {
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) {
if (result.errCode == 0) {
let _errCode = result.reply.readInt();
callback(_errCode);
} else {
console.log("sendRequest failed, errCode: " + result.errCode);
console.log('sendRequest failed, errCode: ' + result.errCode);
}
})
}
......@@ -644,12 +644,12 @@ import nativeMgr from 'nativeManager';
function testIntTransactionCallback(errCode: number, returnValue: number)
{
console.log("errCode: " + errCode + " returnValue: " + returnValue);
console.log('errCode: ' + errCode + ' returnValue: ' + returnValue);
}
function testStringTransactionCallback(errCode: number)
{
console.log("errCode: " + errCode);
console.log('errCode: ' + errCode);
}
function jsProxyTriggerCppStub()
......@@ -660,6 +660,6 @@ function jsProxyTriggerCppStub()
tsProxy.testIntTransaction(10, testIntTransactionCallback);
// invoke testStringTransaction
tsProxy.testStringTransaction("test", testIntTransactionCallback);
tsProxy.testStringTransaction('test', testIntTransactionCallback);
}
```
......@@ -8,8 +8,8 @@
- 快速开始
- 快速入门
- [开发准备](quick-start/start-overview.md)
- [使用eTS语言开发(Stage模型)](quick-start/start-with-ets-stage.md)
- [使用eTS语言开发(FA模型)](quick-start/start-with-ets-fa.md)
- [使用ArkTS语言开发(Stage模型)](quick-start/start-with-ets-stage.md)
- [使用ArkTS语言开发(FA模型)](quick-start/start-with-ets-fa.md)
- [使用JS语言开发(FA模型)](quick-start/start-with-js-fa.md)
- 开发基础知识
- [应用包结构说明(FA模型)](quick-start/package-structure.md)
......@@ -26,6 +26,7 @@
- [安全](security/Readme-CN.md)
- [网络与连接](connectivity/Readme-CN.md)
- [数据管理](database/Readme-CN.md)
- [文件管理](file-management/Readme-CN.md)
- [电话服务](telephony/Readme-CN.md)
- [任务管理](task-management/Readme-CN.md)
- [设备管理](device/Readme-CN.md)
......
......@@ -10,7 +10,7 @@
只有app/Context中的方法属于FA模型对应的Context。该模式下,应用级别的Context和Ability级别的Context都是该类型的实例,如果在应用级别的Context里面调用了Ability级别的方法,会产生错误。所以开发者需要注意Context实例所代表的实际含义。
- Stage模型
除了app/Context之外的Context都属于Stage模型,分别有application/Context、application/ApplicationContext、application/AbilityStageContext、application/ExtensionContext、application/AbilityContext、application/FormExtensionContext等Context。这些Context的介绍及使用方式将会在[Stage模型和Context详细介绍](#stage模型和context详细介绍)中进行说明。
除了app/Context之外的Context都属于Stage模型,分别有application/Context、application/ApplicationContext、application/AbilityStageContext、application/ExtensionContext、application/AbilityContext、application/FormExtensionContext等Context。这些Context的介绍及使用方式将会在[Stage模型的Context详细介绍](#stage模型的context详细介绍)中进行说明。
![contextIntroduction](figures/contextIntroduction.png)
......@@ -54,7 +54,7 @@ setDisplayOrientation(orientation: bundle.DisplayOrientation): Promise<void>;
示例:
```javascript
import featureAbility from '@ohos.ability.featureAbility'
import bundle from '../@ohos.bundle';
import bundle from '@ohos.bundle';
export default {
onCreate() {
......@@ -71,13 +71,13 @@ export default {
}
```
## Stage模型Context详细介绍
## Stage模型Context详细介绍
​ Stage模型有如下几类Context:
### application/Context
​ application/Context类型的Context是基类Context,里面提供了应用的一些基础信息:resourceManager、applicationInfo、cacheDir、area等,还有应用的一些基本方法:createBundleContext等。
​ application/Context是基类Context。里面提供了应用的一些基础信息:resourceManager、applicationInfo、cacheDir、area等,还有应用的一些基本方法:createModuleContext等。
**d.ts声明**
......
......@@ -12,20 +12,20 @@ continuationManager作为流转能力的入口,主要用于拉起系统中的
## 接口说明
| 接口名 | 接口描述 |
| ---------------------------------------------------------------------------------------------- | ----------- |
| register(callback: AsyncCallback\<number>): void | 注册流转管理服务,并获取对应的注册token,无过滤条件(AsyncCallback)。 |
| register(options: ContinuationExtraParams, callback: AsyncCallback\<number>): void | 注册流转管理服务,并获取对应的注册token(AsyncCallback)。 |
| register(options?: ContinuationExtraParams): Promise\<number> | 连接流转管理服务,并获取对应的注册token(Promise)。 |
| registerContinuation(callback: AsyncCallback\<number>): void | 注册流转管理服务,并获取对应的注册token,无过滤条件(AsyncCallback)。 |
| registerContinuation(options: ContinuationExtraParams, callback: AsyncCallback\<number>): void | 注册流转管理服务,并获取对应的注册token(AsyncCallback)。 |
| registerContinuation(options?: ContinuationExtraParams): Promise\<number> | 连接流转管理服务,并获取对应的注册token(Promise)。 |
| on(type: "deviceConnect", token: number, callback: Callback\<Array\<ContinuationResult>>): void | 监听设备连接状态(Callback)。 |
| on(type: "deviceDisconnect", token: number, callback: Callback\<Array\<string>>): void | 监听设备断开状态(Callback)。 |
| off(type: "deviceConnect", token: number): void | 取消监听设备连接状态。 |
| off(type: "deviceDisconnect", token: number): void | 取消监听设备断开状态。 |
| startDeviceManager(token: number, callback: AsyncCallback\<void>): void | 拉起设备选择模块,可显示组网内可选择设备列表信息,无过滤条件(AsyncCallback)。 |
| startDeviceManager(token: number, options: ContinuationExtraParams, callback: AsyncCallback\<void>): void | 拉起设备选择模块,可显示组网内可选择设备列表信息(AsyncCallback)。 |
| startDeviceManager(token: number, options?: ContinuationExtraParams): Promise\<void> | 拉起设备选择模块,可显示组网内可选择设备列表信息(Promise)。 |
| updateConnectStatus(token: number, deviceId: string, status: DeviceConnectState, callback: AsyncCallback\<void>): void | 通知设备选择模块,更新当前的流转状态(AsyncCallback)。 |
| updateConnectStatus(token: number, deviceId: string, status: DeviceConnectState): Promise\<void> | 通知设备选择模块,更新当前的流转状态(Promise)。 |
| unregister(token: number, callback: AsyncCallback\<void>): void | 取消注册流转管理服务,传入注册时获取的token进行取消注册(AsyncCallback)。 |
| unregister(token: number): Promise\<void> | 取消注册流转管理服务,传入注册时获取的token进行取消注册(Promise)。 |
| startContinuationDeviceManager(token: number, callback: AsyncCallback\<void>): void | 拉起设备选择模块,可显示组网内可选择设备列表信息,无过滤条件(AsyncCallback)。 |
| startContinuationDeviceManager(token: number, options: ContinuationExtraParams, callback: AsyncCallback\<void>): void | 拉起设备选择模块,可显示组网内可选择设备列表信息(AsyncCallback)。 |
| startContinuationDeviceManager(token: number, options?: ContinuationExtraParams): Promise\<void> | 拉起设备选择模块,可显示组网内可选择设备列表信息(Promise)。 |
| updateContinuationState(token: number, deviceId: string, status: DeviceConnectState, callback: AsyncCallback\<void>): void | 通知设备选择模块,更新当前的流转状态(AsyncCallback)。 |
| updateContinuationState(token: number, deviceId: string, status: DeviceConnectState): Promise\<void> | 通知设备选择模块,更新当前的流转状态(Promise)。 |
| unregisterContinuation(token: number, callback: AsyncCallback\<void>): void | 取消注册流转管理服务,传入注册时获取的token进行取消注册(AsyncCallback)。 |
| unregisterContinuation(token: number): Promise\<void> | 取消注册流转管理服务,传入注册时获取的token进行取消注册(Promise)。 |
## 开发步骤
1. 导入continuationManager模块。
......@@ -138,13 +138,16 @@ continuationManager作为流转能力的入口,主要用于拉起系统中的
```ts
let token: number = -1; // 用于保存注册成功并返回的token,后续使用其完成监听设备连接/断开状态、拉起设备选择模块以及更新流转状态的动作
continuationManager.register().then((data) => {
console.info('register finished, ' + JSON.stringify(data));
try {
continuationManager.registerContinuation().then((data) => {
console.info('registerContinuation finished, ' + JSON.stringify(data));
token = data; // 获取到对应的注册token,并赋值给token变量
}).catch((err) => {
console.error('register failed, cause: ' + JSON.stringify(err));
console.error('registerContinuation failed, cause: ' + JSON.stringify(err));
});
} catch (err) {
console.error('registerContinuation failed, cause: ' + JSON.stringify(err));
}
```
4. 监听设备状态。
......@@ -154,6 +157,7 @@ continuationManager作为流转能力的入口,主要用于拉起系统中的
```ts
let remoteDeviceId: string = ""; // 用于保存用户选择的远端设备信息,后续使用其完成跨端迁移或多端协同操作
try {
// 参数token为注册token
continuationManager.on("deviceConnect", token, (continuationResults) => {
console.info('registerDeviceConnectCallback len: ' + continuationResults.length);
......@@ -176,6 +180,9 @@ continuationManager作为流转能力的入口,主要用于拉起系统中的
console.error('StartRemoteAbility failed, cause: ' + JSON.stringify(err));
});
});
} catch (err) {
console.error('on failed, cause: ' + JSON.stringify(err));
}
```
上述多端协同操作为Stage平台的跨设备拉起,FA平台详情见[PageAbility开发指导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ability/fa-pageability.md)
......@@ -187,16 +194,21 @@ continuationManager作为流转能力的入口,主要用于拉起系统中的
let deviceConnectStatus: continuationManager.DeviceConnectState = continuationManager.DeviceConnectState.CONNECTED;
// 参数token为注册token,参数remoteDeviceId为获取到的remoteDeviceId
continuationManager.updateConnectStatus(token, remoteDeviceId, deviceConnectStatus).then((data) => {
console.info('updateConnectStatus finished, ' + JSON.stringify(data));
try {
continuationManager.updateContinuationState(token, remoteDeviceId, deviceConnectStatus).then((data) => {
console.info('updateContinuationState finished, ' + JSON.stringify(data));
}).catch((err) => {
console.error('updateConnectStatus failed, cause: ' + JSON.stringify(err));
console.error('updateContinuationState failed, cause: ' + JSON.stringify(err));
});
} catch (err) {
console.error('updateContinuationState failed, cause: ' + JSON.stringify(err));
}
```
监听设备断开状态,方便用户终止跨端迁移或多端协同操作,代码示例如下:
```ts
try {
// 参数token为注册token
continuationManager.on("deviceDisconnect", token, (deviceIds) => {
console.info('onDeviceDisconnect len: ' + deviceIds.length);
......@@ -210,12 +222,15 @@ continuationManager作为流转能力的入口,主要用于拉起系统中的
let deviceConnectStatus: continuationManager.DeviceConnectState = continuationManager.DeviceConnectState.DISCONNECTING; // 设备断开状态
// 参数token为注册token,参数unselectedDeviceId为获取到的unselectedDeviceId
continuationManager.updateConnectStatus(token, unselectedDeviceId, deviceConnectStatus).then((data) => {
console.info('updateConnectStatus finished, ' + JSON.stringify(data));
continuationManager.updateContinuationState(token, unselectedDeviceId, deviceConnectStatus).then((data) => {
console.info('updateContinuationState finished, ' + JSON.stringify(data));
}).catch((err) => {
console.error('updateConnectStatus failed, cause: ' + JSON.stringify(err));
console.error('updateContinuationState failed, cause: ' + JSON.stringify(err));
});
});
} catch (err) {
console.error('updateContinuationState failed, cause: ' + JSON.stringify(err));
}
```
5. 拉起设备选择模块,可显示组网内可选择设备列表信息,供用户选择。
......@@ -229,12 +244,16 @@ continuationManager作为流转能力的入口,主要用于拉起系统中的
continuationMode: continuationManager.ContinuationMode.COLLABORATION_SINGLE // 设备选择模块单选模式
};
try {
// 参数token为注册token
continuationManager.startDeviceManager(token, continuationExtraParams).then((data) => {
console.info('startDeviceManager finished, ' + JSON.stringify(data));
continuationManager.startContinuationDeviceManager(token, continuationExtraParams).then((data) => {
console.info('startContinuationDeviceManager finished, ' + JSON.stringify(data));
}).catch((err) => {
console.error('startDeviceManager failed, cause: ' + JSON.stringify(err));
console.error('startContinuationDeviceManager failed, cause: ' + JSON.stringify(err));
});
} catch (err) {
console.error('startContinuationDeviceManager failed, cause: ' + JSON.stringify(err));
}
```
6. 当用户不打算再进行跨端迁移或多端协同操作时,可以传入注册时获取的token进行取消注册。
......@@ -242,10 +261,14 @@ continuationManager作为流转能力的入口,主要用于拉起系统中的
取消注册流转管理服务的代码示例如下:
```ts
try {
// 参数token为注册token
continuationManager.unregister(token).then((data) => {
console.info('unregister finished, ' + JSON.stringify(data));
continuationManager.unregisterContinuation(token).then((data) => {
console.info('unregisterContinuation finished, ' + JSON.stringify(data));
}).catch((err) => {
console.error('unregister failed, cause: ' + JSON.stringify(err));
console.error('unregisterContinuation failed, cause: ' + JSON.stringify(err));
});
} catch (err) {
console.error('unregisterContinuation failed, cause: ' + JSON.stringify(err));
}
```
\ No newline at end of file
......@@ -60,7 +60,7 @@
+ **Standard**:每次startAbility调用,都会在应用进程中创建一个该类型的实例,如下图Ability2的两个实例;
+ **Specified**:允许开发者在系统创建AbilityRecord之前,为该实例创建一个key,后续每次创建该类型的Ability实例都会询问应用使用哪个key对应的Ability实例,来响应startAbility请求,如下图Ability3。
+ **Specified**:允许开发者在系统创建Ability实例之前,为该实例创建一个key,后续每次创建该类型的Ability实例都会询问应用使用哪个key对应的Ability实例,来响应startAbility请求,如下图Ability3。
​ 每个Ability实例都对应了一个Launcher Recent中看到的Mission(任务)。
......
# 自动化测试框架使用指南
## 概述
为支撑OpenHarmony操作系统的自动化测试活动开展,我们提供了支持JS/TS语言的单元及UI测试框架,支持开发者针对应用接口或系统接口进行单元测试,并且可基于UI操作进行UI自动化脚本的编写。
本指南重点介绍自动化测试框架的主要功能,同时介绍编写单元/UI自动化测试脚本的方法以及执行过程。
### 简介
OpenHarmony自动化测试框架arkxtest,作为OpenHarmony工具集的重要组成部分,提供了OpenHarmony自动化脚本编写和运行的基础能力。编写方面提供了一系列支持测试脚本编写的API,包括了基础流程API、断言API以及UI操作相关的API,运行方面提供了识别测试脚本、调度执行测试脚本以及汇总测试脚本执行结果的能力。
### 实现原理
框架重要分为两大部分:单元测试框架和UI测试框架。
- 单元测试框架
单元测试框架是测试框架的基础底座,提供了最基本的用例识别、调度、执行及结果汇总的能力。主要功能如下图所示:
![](figures/UnitTest.PNG)
单元测试脚本的基础运行流程如下图所示,依赖aa test命令作为执行入口,该命令可具体参考[对应指南。](../ability/ability-delegator.md)
![](figures/TestFlow.PNG)
- UI测试框架
UI测试框架主要对外提供了[UiTest API](../reference/apis/js-apis-uitest.md)供开发人员在对应测试场景调用,而其脚本的运行基础还是上面提到的单元测试框架。
UI测试框架的主要功能如下图所示:
![](figures/Uitest.PNG)
### 约束与限制
- UI测试框架的能力在OpenHarmony 3.1 release版本之后方可使用,历史版本不支持使用。
- 单元测试框架的部分能力与其版本有关,具体能力与版本匹配信息可见代码仓中的[文档介绍](https://gitee.com/openharmony/testfwk_arkxtest/blob/master/README_zh.md)
## 环境准备
### 环境要求
OpenHarmony自动化脚本的编写主要基于DevEco Studio,并建议使用3.0之后的版本进行脚本编写。
脚本执行需要PC连接OpenHarmony设备,如RK3568开发板等。
### 搭建环境
DevEco Studio可参考其官网介绍进行[下载](https://developer.harmonyos.com/cn/develop/deveco-studio#download),并进行相关的配置动作。
## 新建测试脚本
1. 在DevEco Studio中新建应用开发工程,其中ohos目录即为测试脚本所在的目录。
2. 在工程目录下打开待测试模块下的ets文件,将光标置于代码中任意位置,单击**右键 > Show Context Actions** **> Create Ohos Test**或快捷键**Alt+enter** **> Create Ohos Test**创建测试类,更多指导请参考DevEco Studio中[指导](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-openharmony-test-framework-0000001267284568)
## 编写单元测试脚本
```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));
}
})
}
```
单元测试脚本需要包含如下基本元素:
1、依赖导包,以便使用依赖的测试接口。
2、测试代码编写,主要编写测试代码的相关逻辑,如接口调用等。
3、断言接口调用,设置测试代码中的检查点,如无检查点,则不可认为一个完整的测试脚本。
## 编写UI测试脚本
UI测试脚本是在单元测试框架的基础上编写,主要就是增加了UI测试框架提供的接口调用,实现对应的测试逻辑。
下面的示例代码是在上面的测试脚本基础上增量编写,首先需要增加依赖导包,如下示例代码所示:
```js
import {UiDriver,BY,UiComponent,MatchPattern} from '@ohos.uitest'
```
然后是具体测试代码编写,场景较为简单,就是在启动的应用页面上进行点击操作,然后增加检查点检查用例。
```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));
}
})
}
```
## 执行测试脚本
执行测试脚本可以直接在DevEco Studio中通过点击按钮执行,当前支持以下执行方式:
1、测试包级别执行即执行测试包内的全部用例。
2、测试套级别执行即执行describe方法中定义的全部测试用例。
3、测试方法级别执行即执行指定it方法也就是单条测试用例。
![](figures/Execute.PNG)
## 查看测试结果
测试执行完毕后可直接在DevEco Studio中查看测试结果,如下图示例所示:
![](figures/TestResult.PNG)
# 文件管理
- 媒体库管理
- [媒体库开发概述](medialibrary-overview.md)
- [媒体资源使用指导](medialibrary-resource-guidelines.md)
- [文件路径使用指导](medialibrary-filepath-guidelines.md)
- [相册资源使用指导](medialibrary-album-guidelines.md)
\ No newline at end of file
# 相册资源使用指导
mediaLibrary提供相册相关的接口,供开发者创建、删除相册,获取相册中的图片资源等。
> **说明:**
>
> 在进行功能开发前,请开发者查阅[媒体库开发概述](medialibrary-overview.md),了解如何获取媒体库实例和如何申请媒体库功能开发相关权限。
为了保证应用的运行效率,大部分MediaLibrary调用都是异步的,对于异步调用的API均提供了callback和Promise两种方式,以下示例均采用Promise函数,更多方式可以查阅[API参考](../reference/apis/js-apis-medialibrary.md)
## 获取相册中的图片/视频
获取相册中的图片、视频有两种方式:
一是通过[MediaLibrary.getFileAssets](../reference/apis/js-apis-medialibrary.md#getfileassets7-1)指定相册以获取媒体资源,参考[获取指定相册的媒体资源](medialibrary-resource-guidelines#指定相册)
二是通过[Album.getFileAssets](../reference/apis/js-apis-medialibrary.md#getfileassets7-3)使用相册Album实例获取媒体资源,参考[获取相册中的图片或视频](medialibrary-resource-guidelines#获取相册中的图片或视频)
## 创建相册
通过[MediaLibrary.createAsset](../reference/apis/js-apis-medialibrary.md#createasset8-1)可以创建媒体资源,可以通过创建图片或视频文件时设置的相对路径,创建出相册。相对路径的命名即为相册名称。
**前提条件**
- 获取媒体库mediaLibrary实例。
- 申请媒体库读写权限“ohos.permission.WRITE_MEDIA”。
下面以创建相册myAlbum为例。
**开发步骤**
1. 调用getPublicDirectory获取文件公共路径。
获取文件公共路径的更多指导可参考[获取文件保存的公共目录](medialibrary-filepath-guidelines.md#获取文件保存的公共目录)
2. 调用createAsset新建图片,并设置相对路径为path+'myAlbum/'。
即在创建相册的同时,往里面放了一张图片。
```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为新建文件保存路径,也是新建相册的名称
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);
}
});
}
```
## 重命名相册
重命名修改的是相册的FileAsset.albumName属性,即相册名称。修改后再通过[Album.commitModify](../reference/apis/js-apis-medialibrary.md#commitmodify8-3)更新到数据库中。
**前提条件**
- 获取媒体库mediaLibrary实例。
- 申请媒体库读写权限“ohos.permission.WRITE_MEDIA”。
下面以重命名相册为“newAlbum“为例。
**开发步骤**
1. 建立检索条件,用于获取目标相册。
2. 调用getAlbums获取相册列表。
3. 将相册重命名为“newAlbum“。
4. 调用Album.commitModify将更新的相册属性修改到数据库中。
```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';
//回调返回空
album.commitModify().then(function() {
console.info("albumRename successfully");
}).catch(function(err){
console.info("albumRename failed with error:"+ err);
});
}
```
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册