diff --git a/OAT.xml b/OAT.xml index c18b31e0f12e182059756552ea2d9d0b42600f88..65350456fb39c3f9f78edab14eb33d2ec457a950 100644 --- a/OAT.xml +++ b/OAT.xml @@ -58,7 +58,8 @@ Note:If the text contains special characters, please escape them according to th - + + diff --git a/test/hapAppDcameraSample/.gitignore b/test/hapAppDcameraSample/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/test/hapAppDcameraSample/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/test/hapAppDcameraSample/AppScope/app.json5 b/test/hapAppDcameraSample/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..52abc1bf1edb36eaeaad22bea70ff3bc58fe769e --- /dev/null +++ b/test/hapAppDcameraSample/AppScope/app.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "app": { + "bundleName": "com.example.rm0512demo", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name", + } +} diff --git a/test/hapAppDcameraSample/AppScope/resources/base/element/string.json b/test/hapAppDcameraSample/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..213d3080ee2c35ba44c313e2463a29c6005a7261 --- /dev/null +++ b/test/hapAppDcameraSample/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "RM0512Demo" + } + ] +} diff --git a/test/hapAppDcameraSample/AppScope/resources/base/media/app_icon.png b/test/hapAppDcameraSample/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/test/hapAppDcameraSample/AppScope/resources/base/media/app_icon.png differ diff --git a/test/hapAppDcameraSample/build-profile.json5 b/test/hapAppDcameraSample/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ebd23c5cf83d7c422a7ff44eb28284619f96d8c0 --- /dev/null +++ b/test/hapAppDcameraSample/build-profile.json5 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "app": { + "signingConfigs": [ + { + "name": "default", + "type": "HarmonyOS", + "material": { + "certpath": "C:\\Users\\admin\\.ohos\\config\\default_dcameraSample_MQGVIkitSxUdBu-kMBECw1W0Rx8UVies_9x-1tKD7hc=.cer", + "storePassword": "0000001A0DFB8F6A5166B2EFAE02A902D3A40D38BDB0CC1C505061D261ABA85CBA447876815B88989AD1", + "keyAlias": "debugKey", + "keyPassword": "0000001A0B50FDD9F5979F6DACD8E77D49CC5CDC0C6C83825EFACC3C4301E0284BB8FFA8E65362FA9DD6", + "profile": "C:\\Users\\admin\\.ohos\\config\\default_dcameraSample_MQGVIkitSxUdBu-kMBECw1W0Rx8UVies_9x-1tKD7hc=.p7b", + "signAlg": "SHA256withECDSA", + "storeFile": "C:\\Users\\admin\\.ohos\\config\\default_dcameraSample_MQGVIkitSxUdBu-kMBECw1W0Rx8UVies_9x-1tKD7hc=.p12" + } + } + ], + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.0.1(13)", + "runtimeOS": "HarmonyOS", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true, + "useNormalizedOHMUrl": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/code-linter.json5 b/test/hapAppDcameraSample/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..44d50304643a42f437232b908c9b44c51cea8f60 --- /dev/null +++ b/test/hapAppDcameraSample/code-linter.json5 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/.gitignore b/test/hapAppDcameraSample/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/test/hapAppDcameraSample/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/build-profile.json5 b/test/hapAppDcameraSample/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..384f7363aed3352dbb05f27e16b93245dc32f882 --- /dev/null +++ b/test/hapAppDcameraSample/entry/build-profile.json5 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "apiType": "stageMode", + "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp2/CMakeLists.txt", + "arguments": "", + "cppFlags": "" + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + }, + "nativeLib": { + "debugSymbol": { + "strip": true, + "exclude": [] + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/hvigorfile.ts b/test/hapAppDcameraSample/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..8774588471ede4c1563f09d9a1d22f764bb1fd9e --- /dev/null +++ b/test/hapAppDcameraSample/entry/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/test/hapAppDcameraSample/entry/obfuscation-rules.txt b/test/hapAppDcameraSample/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/test/hapAppDcameraSample/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/oh-package-lock.json5 b/test/hapAppDcameraSample/entry/oh-package-lock.json5 new file mode 100644 index 0000000000000000000000000000000000000000..82a2d60c7a390c81bf7935c900ea933a44dd22a5 --- /dev/null +++ b/test/hapAppDcameraSample/entry/oh-package-lock.json5 @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": {}, + "packages": {} +} diff --git a/test/hapAppDcameraSample/entry/oh-package.json5 b/test/hapAppDcameraSample/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ca5dba866ade0eea1b1617cd5caacc7b8b0e8a8b --- /dev/null +++ b/test/hapAppDcameraSample/entry/oh-package.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/common/ButtonComponent.ets b/test/hapAppDcameraSample/entry/src/main/ets/common/ButtonComponent.ets new file mode 100644 index 0000000000000000000000000000000000000000..9a6761392b89cba235e13b3214692cdd1e22ccf2 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/common/ButtonComponent.ets @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { obtainImgVertical, obtainImgV, obtainImgVs } from '../utils/ImageList' + +interface ImageList { + image: Resource + value: string +} + +@Component +export struct ButtonComponent { + private onInputValue: (result: string) => void = () => { + } + + build() { + Row() { + Grid() { + ForEach(obtainImgV(), (item: ImageList, index: number | undefined) => { + GridItem() { + Button({ type: ButtonType.Normal }) { + Image(item.image) + .width('45%') + .height('35%') + .objectFit(ImageFit.Cover) + } + .id(item.value) + .width('100%') + .height('100%') + .borderRadius('16px') + .backgroundColor(index !== undefined && index < 2 ? '#33007DFF' : '#FF006CDE') + .onClick(() => { + this.onInputValue(item.value) + }) + } + .rowStart(index !== undefined ? index : 0) + .rowEnd(index !== undefined && index === 2 ? (index !== undefined ? index + 1 : 0) : (index !== undefined ? index : 0)) + .columnStart(4) + .columnEnd(4) + }) + ForEach(obtainImgVs(), (item: ImageList, index) => { + GridItem() { + Button({ type: ButtonType.Normal }) { + Image(item.image) + .width('45%') + .height('35%') + .objectFit(ImageFit.Cover) + } + .id(item.value) + .width('100%') + .height('100%') + .borderRadius('16px') + .backgroundColor('#33007DFF') + .onClick(() => { + this.onInputValue(item.value) + }) + } + .rowStart(index !== undefined ? index : 0) + .rowEnd(index !== undefined ? index : 0) + .columnStart(3) + .columnEnd(3) + }) + ForEach(obtainImgVertical(), (item: ImageList, index) => { + GridItem() { + Button({ type: ButtonType.Normal }) { + Image(item.image) + .width('55%') + .height('55%') + .objectFit(ImageFit.Cover) + } + .id(item.value) + .width('100%') + .height('100%') + .borderRadius('16px') + .backgroundColor('#F0F0F0') + .onClick(() => { + this.onInputValue(item.value) + }) + } + .columnStart(index === undefined ? 0 : index % 3) + .columnEnd(index !== undefined && item.value === '0' ? (index % 3 + 1) : index !== undefined ? index % 3 : 0) + }) + } + .columnsGap(5) + .rowsGap(5) + .columnsTemplate('1fr 1fr 1fr 1fr 1fr') + .rowsTemplate('1fr 1fr 1fr 1fr ') + } + .padding(10) + .size({ width: '100%', height: '56%' }) + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/common/ButtonComponentHorizontal.ets b/test/hapAppDcameraSample/entry/src/main/ets/common/ButtonComponentHorizontal.ets new file mode 100644 index 0000000000000000000000000000000000000000..37f28a99ac2709511b231f2e2ad7c04909ff8494 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/common/ButtonComponentHorizontal.ets @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { obtainImgLevel, obtainImg, obtainImgL } from '../utils/ImageList' + +interface ImageList { + image: Resource + value: string +} + +@Component +export struct ButtonComponentHorizontal { + private onInputValue: (result: string) => void = () => { + } + + build() { + Column() { + Grid() { + ForEach(obtainImg(), (item: ImageList, index) => { + GridItem() { + Button({ type: ButtonType.Normal }) { + Image(item.image) + .height('100%') + .aspectRatio(index !== undefined && index < 2 ? 1 : 0.5) + .objectFit(ImageFit.Contain) + } + .id(item.value) + .width('100%') + .height('100%') + .borderRadius(20) + .backgroundColor(index !== undefined && index < 2 ? '#33007DFF' : '#007DFF') + .onClick(() => { + this.onInputValue(item.value) + }) + } + .rowStart(index !== undefined ? index : 0) + .rowEnd(index !== undefined && index === 2 ? (index !== undefined ? index + 1 : 0) : (index !== undefined ? index : 0)) + .columnStart(4) + .columnEnd(4) + }) + ForEach(obtainImgLevel(), (item:ImageList, index) => { + GridItem() { + Button({ type: ButtonType.Normal }) { + Image(item.image) + .height('100%') + .aspectRatio(item.value === '0' ? 2.5 : 1) + .objectFit(ImageFit.Contain) + } + .id(item.value) + .width('100%') + .height('100%') + .borderRadius(20) + .backgroundColor((index !== undefined && index % 4 >= 3) || item.value === '+' ? '#33007DFF' : '#F0F0F0') + .onClick(() => { + this.onInputValue(item.value) + }) + } + .columnStart(index !== undefined ? index % 4 : 0) + .columnEnd(item.value === '0' ? (index !== undefined ? index % 4 + 1 : 0) : index !== undefined ? index % 4 : 0) + }) + } + .width('80%') + .columnsGap(10) + .rowsGap(10) + .columnsTemplate('1fr 1fr 1fr 1fr 1fr') + .rowsTemplate('1fr 1fr 1fr 1fr') + } + .padding(10) + .size({ width: '70%', height: '90%' }) + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/common/DeviceDialog.ets b/test/hapAppDcameraSample/entry/src/main/ets/common/DeviceDialog.ets new file mode 100644 index 0000000000000000000000000000000000000000..41d2a087f84f8345f617c3a845d4b5e4f0586ce6 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/common/DeviceDialog.ets @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import deviceManager from '@ohos.distributedDeviceManager'; +import Logger from '../utils/Logger' + +const TAG: string = 'Sample_DeviceDialog' + +@CustomDialog +export struct DeviceDialog { + controller?: CustomDialogController; + @StorageLink('deviceList') deviceList: Array = AppStorage.get('deviceList')!; + private selectedIndex: number | undefined = 0; + private onSelectedIndexChange: (selectedIndex: number | undefined) => void = () => { + } + @State deviceDialogWidth: number = 0 + + build() { + Column() { + Text($r('app.string.choiceDevice')) + .fontSize(px2vp(30)) + .width('100%') + .height('20%') + .fontColor(Color.Black) + .textAlign(TextAlign.Start) + List() { + ForEach(this.deviceList, (item: deviceManager.DeviceBasicInfo, index: number | undefined) => { + ListItem() { + Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween }) { + Text(item.deviceName) + .fontSize(px2vp(30)) + .width('100%') + .fontColor(Color.Black) + } + .margin({ top: 17 }) + .enabled(true) + .backgroundColor(Color.Gray) + .onClick(() => { + Logger.info(TAG, `select device: ${item.deviceId}`) + if (this.selectedIndex !== undefined) { + Logger.info(TAG, `onSelectedIndexChange: ${index}`) + console.log(TAG, this.onSelectedIndexChange); + this.selectedIndex = index + this.onSelectedIndexChange(this.selectedIndex) + } + }) + } + .width('100%') + .height('50%') + }, (item: deviceManager.DeviceBasicInfo) => item.deviceName) + } + .height('60%') + .width('100%') + .layoutWeight(1) + + Button() { + Text($r('app.string.cancel')) + .width('90%') + .fontSize(21) + .fontColor('#ff0d64fb') + .textAlign(TextAlign.Center) + } + .type(ButtonType.Capsule) + .backgroundColor(Color.White) + .onClick(() => { + if (this.controller !== undefined) { + this.controller.close() + } + }) + } + .margin({ bottom: 15 }) + .onAreaChange((oldArea: Area, newArea: Area) => { + this.deviceDialogWidth = + (newArea.width > newArea.height ? newArea.height : newArea.width) as number * 0.1 //percentage + }) + .width('80%') + .height(px2vp(240)) + .padding({ left: 18, right: 32 }) + .backgroundColor(Color.White) + .border({ color: Color.White, radius: 20 }) + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/common/InputComponent.ets b/test/hapAppDcameraSample/entry/src/main/ets/common/InputComponent.ets new file mode 100644 index 0000000000000000000000000000000000000000..4a588dc900b6046c1dd0dd5f1c052b7612400c03 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/common/InputComponent.ets @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@Component +export struct InputComponent { + @Link result: string + @Link expression: string + private isLand: boolean = false + + build() { + Stack({ alignContent: this.isLand ? Alignment.BottomStart : Alignment.TopEnd }) { + Column() { + Row() { + Text(this.expression) + .margin({ top: '3%' }) + .height('100%') + .width('100%') + .id('expression') + .opacity(0.9) + .fontWeight(400) + .textAlign(TextAlign.Start) + .fontSize(this.isLand ? '50px' : '35px') + } + .height('48%') + .width('90%') + .align(this.isLand ? Alignment.End : Alignment.Start) + Row() { + Text(this.result) + .margin({ top: '1%' }) + .height('100%') + .width('100%') + .id('result') + .opacity(0.38) + .textAlign(TextAlign.Start) + .fontSize(this.isLand ? '50px' : '31px') + .margin(this.isLand ? { bottom: 64 } : {}) + } + .height('46%') + .width('90%') + .align(this.isLand ? Alignment.End : Alignment.Start) + } + .width('100%') + .align(Alignment.Center) + } + .width(this.isLand ? '34%' : '100%') + .height(this.isLand ? '100%' : '34%') + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/common/TitleBarComponent.ets b/test/hapAppDcameraSample/entry/src/main/ets/common/TitleBarComponent.ets new file mode 100644 index 0000000000000000000000000000000000000000..ad9f2e64ecbe41e9bebb87853c2b8e4fdcefd800 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/common/TitleBarComponent.ets @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import deviceManager from '@ohos.distributedDeviceManager'; +import Logger from '../utils/Logger' +import { DeviceDialog } from '../common/DeviceDialog' +import { RemoteDeviceModel, BUNDLE_NAME } from '../recorder/RemoteDeviceModel' +import common from '@ohos.app.ability.common' +import Want from '@ohos.app.ability.Want'; +import { router } from '@kit.ArkUI'; + +const TAG: string = 'Sample_TitleBarComponent' +const DATA_CHANGE: string = 'dataChange' +const EXIT: string = 'exit' +const DEVICE_DISCOVERY_RANGE: number = 1000 + +@Component +export struct TitleBarComponent { + @Prop isLand: boolean | null = null + @State selectedIndex: number | undefined = 0 + @StorageLink('deviceList') deviceList: Array = [] + private isShow: boolean = false + private startAbilityCallBack: (key: string) => void = () => { + } + private dialogController: CustomDialogController | null = null + private remoteDeviceModel: RemoteDeviceModel = new RemoteDeviceModel() + onSelectedIndexChange = (index: number | undefined) => { + Logger.info(TAG, `selectedIndexChange`) + this.selectedIndex = index + this.dialogController?.close() + /*if (this.selectedIndex === 0) { + Logger.info(TAG, `stop ability`) + this.deviceList = [] + if (this.dialogController !== null) { + this.dialogController.close() + } + return + }*/ + this.selectDevice() + } + + aboutToAppear() { + AppStorage.setOrCreate('deviceList', this.deviceList) + } + + clearSelectState() { + this.deviceList = [] + if (this.dialogController !== null) { + this.dialogController.close() + } + Logger.info(TAG, `cancelDialog`) + if (this.remoteDeviceModel === undefined) { + return + } + this.remoteDeviceModel.unregisterDeviceListCallback() + } + + selectDevice() { + if (this.selectedIndex !== undefined && (this.remoteDeviceModel === null || this.remoteDeviceModel.discoverList.length <= 0)) { + Logger.info(TAG, `continue unauthed device: ${JSON.stringify(this.deviceList)}`) + this.clearSelectState() + return + } + Logger.info(TAG, `needAuth:`) + if (this.selectedIndex !== undefined) { + console.log(TAG, ",", this.deviceList.length, "," , this.deviceList[this.selectedIndex].deviceName); + + this.remoteDeviceModel.authenticateDevice(this.deviceList[this.selectedIndex], () => { + Logger.info(TAG, `auth and online finished`); + if (this.remoteDeviceModel !== null && this.remoteDeviceModel.deviceList !== null && this.selectedIndex !== undefined) { + for (let i = 0; i < this.remoteDeviceModel.deviceList!.length; i++) { + if (this.remoteDeviceModel.deviceList![i].deviceName === this.deviceList[this.selectedIndex].deviceName) { + } + } + } + }) + } + this.clearSelectState() + } + + showDiainfo() { + this.deviceList = [] + // 注册监听回调,发现设备或查找到已认证设备会弹窗显示 + this.remoteDeviceModel.registerDeviceListCallback(() => { + this.deviceList = [] + let context: common.UIAbilityContext | undefined = AppStorage.get('UIAbilityContext') + if (context !== undefined) { + this.deviceList.push({ + deviceId: '0', + deviceName: context.resourceManager.getStringSync($r('app.string.localhost').id), + deviceType: '0', + networkId: '' + }) + } + let deviceTempList = this.remoteDeviceModel.discoverList.length > 0 ? this.remoteDeviceModel.discoverList : this.remoteDeviceModel.deviceList; + if (deviceTempList !== null) { + for (let i = 0; i < deviceTempList!.length; i++) { + Logger.info(TAG, `found device ${i}/${deviceTempList!.length} deviceId= ${deviceTempList![i].deviceId}, deviceName= ${deviceTempList![i].deviceName}, deviceType= ${deviceTempList![i].deviceType}`); + if (deviceTempList !== null) { + this.deviceList.push({ + deviceId: deviceTempList![i].deviceId, + deviceName: deviceTempList![i].deviceName, + deviceType: deviceTempList![i].deviceType, + networkId: deviceTempList![i].networkId, + }) + AppStorage.set('deviceList', this.deviceList) + } + } + } + }) + if (this.dialogController === null) { + this.dialogController = new CustomDialogController({ + builder: DeviceDialog({ + selectedIndex: this.selectedIndex, + onSelectedIndexChange: this.onSelectedIndexChange + }), + cancel: () => { + this.clearSelectState() + }, + autoCancel: true, + alignment: this.isLand ? DialogAlignment.Center : DialogAlignment.Bottom, + customStyle: false + }) + } + if (this.dialogController !== null) { + this.dialogController.open() + } + } + + build() { + Row() { + Image($r('app.media.ic_back')) + .height('60%') + .margin({ left: '5%' }) + .width('50px') + .objectFit(ImageFit.Contain) + .onClick(async () => { + //let context = getContext(this) as common.UIAbilityContext + //context.terminateSelf() + router.back(); + }) + Text("back") + .height('60%') + .fontSize('28px') + .margin({ left: 12 }) + Blank().layoutWeight(1) + if (!this.isShow) { + Image($r("app.media.ic_hop_normal1")) + .id('selectDevice') + .margin({ right: 32 }) + .width('9%') + .margin({ right: '12%' }) + .objectFit(ImageFit.Contain) + .onClick(() => { + this.showDiainfo() + //router.back(); + }) + } + } + .width('100%') + .height(this.isLand ? '10%' : '6%') + .constraintSize({ minHeight: 50 }) + .alignItems(VerticalAlign.Center) + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/entryability/EntryAbility.ts b/test/hapAppDcameraSample/entry/src/main/ets/entryability/EntryAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f5e1027543fba54fdc0e0a4aff8b16b2e30c9d5 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/entryability/EntryAbility.ts @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { UIAbility } from '@kit.AbilityKit'; +import { window } from '@kit.ArkUI'; +import { abilityAccessCtrl } from '@kit.AbilityKit'; +import { Permissions } from '@kit.AbilityKit'; +import Logger from '../utils/Logger'; +import { BusinessError } from '@ohos.base'; + +/** + * Lift cycle management of Ability. + */ +export default class EntryAbility extends UIAbility { + onCreate(want, launchParam) { + Logger.info('Sample_VideoRecorder', 'Ability onCreate,requestPermissionsFromUser'); + let permissionNames: Array = ['ohos.permission.MEDIA_LOCATION', 'ohos.permission.READ_MEDIA', + 'ohos.permission.WRITE_MEDIA', 'ohos.permission.CAMERA', 'ohos.permission.MICROPHONE', + 'ohos.permission.DISTRIBUTED_DATASYNC']; + abilityAccessCtrl.createAtManager().requestPermissionsFromUser(this.context, permissionNames).then((data) => { + console.log("Sample_VideoRecorder", data); + }).catch((err: BusinessError) => { + console.log("Sample_VideoRecorder", err.message); + }); + } + + onDestroy() { + Logger.info('Sample_VideoRecorder', 'Ability onDestroy'); + } + + async onWindowStageCreate(windowStage: window.WindowStage) { + // Main window is created, set main page for this ability + Logger.info('Sample_VideoRecorder', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/ListPage', (err, data) => { + if (err.code) { + Logger.error('Sample_VideoRecorder', 'Failed to load the content. Cause: ' + JSON.stringify(err)); + return; + } + Logger.info('Sample_VideoRecorder', 'Succeeded in loading the content. Data: ' + JSON.stringify(data)); + windowStage.getMainWindow().then((win: window.Window) => { + win.setKeepScreenOn(true); + }) + }); + } + + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + Logger.info('Sample_VideoRecorder', 'Ability onWindowStageDestroy'); + } + + onForeground() { + // Ability has brought to foreground + Logger.info('Sample_VideoRecorder', 'Ability onForeground'); + } + + onBackground() { + // Ability has back to background + Logger.info('Sample_VideoRecorder', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/test/hapAppDcameraSample/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..69a47ce6bf1d1e2d0c5a0f0432a8bb83ef1daae4 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/pages/Index.ets b/test/hapAppDcameraSample/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..ff1bd620c43aa111685245ef2b8758f95313d1ba --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { hilog } from '@kit.PerformanceAnalysisKit'; +// import testNapi from 'libentry.so'; + +@Entry +@Component +struct Index { + @State message: string = 'Hello World'; + + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + .onClick(() => { + // hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.add(2, 3)); + }) + } + .width('100%') + } + .height('100%') + } +} diff --git a/test/hapAppDcameraSample/entry/src/main/ets/pages/ListPage.ets b/test/hapAppDcameraSample/entry/src/main/ets/pages/ListPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..fad80ae403d7a7e671ade586e2ef3c45bd531459 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/pages/ListPage.ets @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { router } from '@kit.ArkUI'; +import Logger from '../utils/Logger'; + +@Entry +@Component +struct ListPage { + build() { + Column() { + Text($r('app.string.page_title')) + .fontFamily('HarmonyHeiTi-Bold') + .fontSize(24) + .fontColor($r('app.color.title_color')) + .height(33) + .width(312) + .margin({left: 24, right:24, top:12, bottom: 12}) + Button() { + Text($r('app.string.page_title_video')) + .fontFamily('HarmonyHeiTi-Medium') + .width(64) + .height(20) + .fontColor($r('app.color.title_color')) + .fontSize(16) + .margin({left: 12, right:336, top:12, bottom: 12}) + } + .id('videoRecorderPage') + .height(48) + .backgroundColor($r('app.color.button_background')) + .borderRadius(24) + .onClick(() => { + router.pushUrl({ + url: 'recorder/VideoRecorder', + }) + }) + .margin({ left: 12, right:12, top: 0, bottom:12}) + Button() { + Text($r('app.string.page_title_audio')) + .fontFamily('HarmonyHeiTi-Medium') + .width(64) + .height(20) + .fontColor($r('app.color.title_color')) + .fontSize(16) + .margin({left: 12, right:336, top:12, bottom: 12}) + } + .id('audioRecorderPage') + .height(48) + .backgroundColor($r('app.color.button_background')) + .borderRadius(24) + .onClick(() => { + router.pushUrl({ + url: 'recorder/AudioRecorder', + }) + }) + .margin({ left: 12, right:12, top: 0, bottom:12}) + } + .backgroundColor($r('app.color.homepage_background')) + .width('100%') + .height('100%') + .alignItems(HorizontalAlign.Start) + } +} diff --git a/test/hapAppDcameraSample/entry/src/main/ets/recorder/AudioRecorder.ets b/test/hapAppDcameraSample/entry/src/main/ets/recorder/AudioRecorder.ets new file mode 100644 index 0000000000000000000000000000000000000000..88e8c88ecf26be82d534074f1681981e85cff2b8 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/recorder/AudioRecorder.ets @@ -0,0 +1,488 @@ +/* + * Copyright (C) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { media } from '@kit.MediaKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { dateTime } from '../utils/DateTimeUtils'; +import Logger from '../utils/Logger'; +import SaveCameraAsset from '../utils/SaveCameraAsset'; + +const TAG: string = 'Sample_AudioRecorder'; + +@Entry +@Component +struct AudioRecording { + private audioRecorder?: media.AVRecorder; + private fdPath?: string = ''; + @State frameRate: number = 15; + @State audioRecorderTimeText: string = '00:00'; + private seconds: number = 0; + private timer: number = 0; + @State displayLog: string = ''; + private recorderState: string = 'free'; + @State isStartRecording: boolean = false; + @State isPauseRecording: boolean = false; + private mSaveCameraAsset: SaveCameraAsset = new SaveCameraAsset(TAG); + private mFileAssetId?: number = 0; // init fd 0 + @State audioChannels: number = 2; // set default audioChannels 2 + @State audioSampleRate: number = 48000; // set default audioSampleRate 48000 + + private avProfile: media.AVRecorderProfile = { + audioBitrate: 64000, // set audioBitrate according to device ability + audioChannels: 1, // set audioChannels, valid value 1-8 + audioCodec: media.CodecMimeType.AUDIO_AAC, // set audioCodec, AUDIO_AAC is the only choice + audioSampleRate: 8000, // set audioSampleRate according to device ability + fileFormat: media.ContainerFormatType.CFT_MPEG_4A, // set fileFormat, for video is m4a + } + private avConfig: media.AVRecorderConfig = { + audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, + profile: this.avProfile, + url: 'fd://' + } + + aboutToAppear(): void { + Logger.info(TAG, 'aboutToAppear called'); + Logger.info(TAG, 'aboutToAppear done'); + } + + aboutToDisappear(): void { + Logger.info(TAG, 'aboutToDisappear called'); + Logger.info(TAG, 'aboutToDisappear done'); + } + + async failureCallback(error: BusinessError): Promise { + Logger.info(TAG, 'case failureCallback called,errMessage is ' + JSON.stringify(error)); + } + + async catchCallback(error: BusinessError): Promise { + Logger.info(TAG, 'case catchCallback called,errMessage is ' + JSON.stringify(error)); + } + + // show recording time + getRecordTime(): void { + this.timer = setInterval(() => { + this.seconds += 1; + this.audioRecorderTimeText = dateTime(this.seconds); + }, 1000) + } + + // create file fd + async getFileFd(): Promise { + Logger.info(TAG, 'getFileFd called'); + this.mFileAssetId = await this.mSaveCameraAsset.createAudioFd(); + this.fdPath = 'fd://' + this.mFileAssetId.toString(); + this.avConfig.url = this.fdPath; + Logger.info(TAG, 'fdPath is: ' + this.fdPath); + Logger.info(TAG, 'getFileFd done'); + } + + async createAudioRecorder(): Promise { + await media.createAVRecorder().then((recorder) => { + Logger.info(TAG, 'case createAVRecorder called'); + if (typeof (recorder) !== 'undefined') { + this.audioRecorder = recorder; + } else { + Logger.info(TAG, 'case create avRecorder failed!!!'); + return + } + }, this.failureCallback).catch(this.catchCallback); + this.setCallback(); + } + + // set callback on + setCallback(): void { + Logger.info(TAG, 'case callback'); + if (this.audioRecorder) { + this.audioRecorder.on('stateChange', (state, reason) => { + Logger.info(TAG, 'case state has changed, new state is' + state); + switch (state) { + case 'idle': + this.recorderState = 'idle'; + break; + case 'prepared': + this.recorderState = 'prepared'; + break; + case 'started': + this.recorderState = 'started'; + this.getRecordTime(); + this.isStartRecording = true; + this.isPauseRecording = false; + break; + case 'paused': + this.recorderState = 'paused'; + clearInterval(this.timer); + this.isPauseRecording = true; + break; + case 'stopped': + this.recorderState = 'stopped'; + this.isStartRecording = false; + break; + case 'released': + this.recorderState = 'released'; + break; + case 'error': + Logger.info(TAG, 'case error state!!!'); + this.recorderState = 'error'; + break; + default: + Logger.info(TAG, 'case start is unknown'); + break; + } + }); + this.audioRecorder.on('error', (err) => { + Logger.info(TAG, 'case avRecorder.on(error) called, errMessage is ' + err.message); + }); + } + } + + async prepareAudioRecorder(): Promise { + Logger.info(TAG, 'case prepareAudioRecorder in'); + this.avConfig.profile.audioChannels = this.audioChannels; + this.avConfig.profile.audioSampleRate = this.audioSampleRate; + if (this.audioRecorder) { + await this.audioRecorder.prepare(this.avConfig).then(() => { + Logger.info(TAG, 'case prepare AVRecorder called'); + }, this.failureCallback).catch(this.catchCallback); + } + Logger.info(TAG, 'case prepareAudioRecorder out'); + } + + async startAudioRecording(): Promise { + Logger.info(TAG, 'case startAudioRecording called'); + if (this.audioRecorder) { + await this.audioRecorder.start().then(() => { + Logger.info(TAG, 'case start AudioRecorder called'); + }, this.failureCallback).catch(this.catchCallback); + } + } + + async pauseAudioRecording(): Promise { + Logger.info(TAG, 'case pauseAudioRecording called'); + if (this.audioRecorder) { + await this.audioRecorder.pause().then(() => { + Logger.info(TAG, 'case pause AudioRecorder called'); + }, this.failureCallback).catch(this.catchCallback); + } + } + + async resumeAudioRecording(): Promise { + Logger.info(TAG, 'case resumeAudioRecording called'); + if (this.audioRecorder) { + await this.audioRecorder.resume().then(() => { + Logger.info(TAG, 'case resume AudioRecorder called'); + }, this.failureCallback).catch(this.catchCallback); + } + } + + async stopAudioRecording(): Promise { + Logger.info(TAG, 'case stopAudioRecording called'); + if (this.audioRecorder) { + await this.audioRecorder.stop().then(() => { + Logger.info(TAG, 'case stop AudioRecorder called'); + }, this.failureCallback).catch(this.catchCallback); + } + } + + async resetAudioRecording(): Promise { + if (this.audioRecorder) { + await this.audioRecorder.reset().then(() => { + Logger.info(TAG, 'case resetAudioRecording called'); + }, this.failureCallback).catch(this.catchCallback); + } + } + + async releaseAudioRecorder(): Promise { + if (this.audioRecorder) { + this.audioRecorder.off('stateChange'); + this.audioRecorder.off('error'); + await this.audioRecorder.release().then(() => { + Logger.info(TAG, 'case releaseAudioRecorder called'); + }, this.failureCallback).catch(this.catchCallback); + this.audioRecorder = undefined; + } + } + + // close file fd + async closeFd(): Promise { + Logger.info(TAG, 'case closeFd called'); + if (this.mSaveCameraAsset) { + await this.mSaveCameraAsset.closeAudioFile(); + this.mFileAssetId = undefined; + this.fdPath = undefined; + Logger.info(TAG, 'case closeFd done'); + } + } + + // start button process + async startRecordingProcess(): Promise { + Logger.info(TAG, 'startRecording called'); + if (this.audioRecorder) { + Logger.info(TAG, 'audioRecorder exist,release it'); + await this.audioRecorder.release(); + } + await this.createAudioRecorder(); + await this.getFileFd(); + await this.prepareAudioRecorder(); + await this.startAudioRecording(); + Logger.info(TAG, 'startRecording done'); + } + + // pause button process + async pauseRecordingProcess(): Promise { + Logger.info(TAG, 'pauseRecording called'); + if (this.recorderState === 'started') { + Logger.info(TAG, 'current state is started, to pause'); + await this.pauseAudioRecording(); + } + Logger.info(TAG, 'pauseRecording done'); + } + + // resume button process + async resumeRecordingProcess(): Promise { + Logger.info(TAG, 'resumeRecording called'); + if (this.recorderState === 'paused') { + Logger.info(TAG, 'current state is paused, to resume'); + await this.resumeAudioRecording(); + } + Logger.info(TAG, 'resumeRecording done'); + } + + // stop button process + async stopRecordingProcess(): Promise { + Logger.info(TAG, 'stopRecording called'); + if (this.recorderState === 'started' || this.recorderState === 'paused') { + await this.stopAudioRecording(); + } + await this.resetAudioRecording(); + await this.releaseAudioRecorder(); + await this.closeFd(); + clearInterval(this.timer); + this.isStartRecording = false; + this.isPauseRecording = false; + this.seconds = 0; + this.audioRecorderTimeText = '00:00'; + Logger.info(TAG, 'stopRecording done'); + } + + build() { + Column() { + Row() { + Stack({ alignContent: Alignment.Center }) { + Text(this.audioRecorderTimeText) + .fontFamily('HarmonyHeiTi-Light') + .width(70) + .height(40) + .fontSize(27) + .fontColor('white') + .margin({ left: 99, top: 13, right: 79, bottom: 703 }) + if (!this.isStartRecording) { + Image($r('app.media.ic_setting')) + .width(40) + .height(40) + .margin({ left: 12, top: 12, right: 308, bottom: 704 }) + .onClick(() => { + if (this.settingDialog !== undefined) { + Logger.info(TAG, 'to open setting dialog'); + this.settingDialog.open() + } + }) + .id('audioSetting') + Image($r('app.media.ic_red_circle')) + .width(12) + .height(12) + .margin({ left: 136, top: 25, right: 212, bottom: 715 }) + Image($r('app.media.take_video_normal')) + .width(86) + .height(86) + .margin({ left: 132, top: 612, right: 132, bottom: 72 }) + .onClick(() => this.startRecordingProcess()) + .id('audioStart') + } + else { + Image($r('app.media.ic_circle_open')) + .width(120) + .height(56) + .margin({ left: 120, top: 632, right: 120, bottom: 92 }) + Image($r('app.media.ic_stop')) + .width(16) + .height(16) + .margin({ left: 146, top: 652, right: 198, bottom: 112 }) + .onClick(() => this.stopRecordingProcess()) + .id('audioStop') + if (!this.isPauseRecording) { + Image($r('app.media.ic_red_circle')) + .width(12) + .height(12) + .margin({ left: 136, top: 25, right: 212, bottom: 715 }) + Image($r('app.media.ic_pause')) + .width(14) + .height(15) + .margin({ left: 200, top: 652, right: 146, bottom: 113 }) + .onClick(() => this.pauseRecordingProcess()) + .id('audioPause') + } else { + Image($r('app.media.ic_small_pause')) + .width(14) + .height(14) + .margin({ left: 136, top: 25, right: 212, bottom: 715 }) + Image($r('app.media.ic_continue')) + .width(16) + .height(16) + .margin({ left: 198, top: 651, right: 144, bottom: 111 }) + .onClick(() => this.resumeRecordingProcess()) + .id('audioResume') + } + } + }.width('100%').height('100%') + }.backgroundColor(Color.Black) + } + } + + onCancel() { + Logger.info(TAG, 'Callback when the cancel button is clicked') + } + + onAccept() { + Logger.info(TAG, 'Callback when the confirm button is clicked') + } + + existApp() { + Logger.info(TAG, 'Click the callback in the blank area') + } + + settingDialog: CustomDialogController = new CustomDialogController({ + builder: CustomDialogSetting({ + cancel: this.onCancel, + confirm: this.onAccept, + audioChannels: $audioChannels, + audioSampleRate: $audioSampleRate, + }), + cancel: this.existApp, + autoCancel: false, + alignment: DialogAlignment.Bottom, + customStyle: true + }) +} + + +@CustomDialog +struct CustomDialogSetting { + @Link audioChannels: number + @Link audioSampleRate: number + controller: CustomDialogController + cancel?: () => void + confirm?: () => void + @State currentAudioChannels: number = 2 + @State currentAudioSampleRate: number = 48000 + private initAudioChannels: number = this.audioChannels + private initAudioSampleRate: number = this.audioSampleRate + @State audioChannelsList: Array = [1, 2] + @State audioSampleRateList: Array = [8000, 22050, 32000, 44100, 48000, 96000] + + build() { + Column() { + Column() { + Text($r('app.string.audio_parameter')) + .fontFamily('HarmonyHeiTi-Medium') + .fontSize(20) + .width(288) + .height(26) + .margin({ left: 24, right: 24, top: 16 }) + Column() { + List({ space: 10 }) { + ForEach(this.audioSampleRateList, (item: number, index) => { + ListItem() { + Row() { + Text($r('app.string.audio_samplerate')) + .fontSize(16) + Text(item.toString()) + .fontSize(16) + .width(160) + if (item == this.initAudioSampleRate) { + Radio({ value: item.toString(), group: 'radioGroup2' }).checked(true) + .height(20) + .id(item.toString()) + .onChange((isChecked: boolean) => { + if (isChecked) { + Logger.info(TAG, item.toString() + ' audioSample is chosen') + this.currentAudioSampleRate = item + } + }) + } else { + Radio({ value: item.toString(), group: 'radioGroup2' }).checked(false) + .height(20) + .onChange((isChecked: boolean) => { + if (isChecked) { + Logger.info(TAG, item.toString() + ' audioSample is chosen') + this.currentAudioSampleRate = item + } + }) + } + }.margin({ left: 0, right: 39 }) + } + }) + }.listDirection(Axis.Vertical) + .divider({ strokeWidth: 0.5, color: '#EEEEEE', startMargin: 0, endMargin: 0 }) + }.margin({ left: 24, right: 24, top: 16 }) + }.alignItems(HorizontalAlign.Start) + + Row() { + Button($r('app.string.button_cancel')) + .onClick(() => { + this.audioChannels = this.initAudioChannels + this.audioSampleRate = this.initAudioSampleRate + this.controller.close() + if (this.cancel) { + this.cancel() + } + }) + .backgroundColor($r('app.color.button_background')) + .fontColor($r('app.color.button_color')) + .fontFamily('HarmonyHeiTi-Medium') + .fontSize(16) + .id('audioCancel') + .layoutWeight(1) + Divider() + .vertical(true) + .height(24) + .color($r('app.color.divider_color')) + .opacity(0.6) + .margin({ left: 8, right: 8 }) + Button($r('app.string.button_confirm')) + .onClick(() => { + this.audioChannels = this.currentAudioChannels + this.audioSampleRate = this.currentAudioSampleRate + this.controller.close() + if (this.confirm) { + this.confirm() + } + }) + .backgroundColor($r('app.color.button_background')) + .fontColor($r('app.color.button_color')) + .fontFamily('HarmonyHeiTi-Medium') + .fontSize(16) + .id('audioConfirm') + .layoutWeight(1) + } + .width(300) + .height(40) + .margin({ top: 12, bottom: 16 }) + } + .margin({ left: 12, right: 12, bottom: 12 }) + .backgroundColor($r('app.color.button_background')) + .borderRadius(32) + .alignItems(HorizontalAlign.Center) + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/recorder/RemoteDeviceModel.ets b/test/hapAppDcameraSample/entry/src/main/ets/recorder/RemoteDeviceModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..5987d24c63409e7174764f419bb240acd8d8fffc --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/recorder/RemoteDeviceModel.ets @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import deviceManager from '@ohos.distributedDeviceManager'; +import Logger from '../utils/Logger' +import { Callback } from '@ohos.base' + +interface deviceData { + device: deviceManager.DeviceBasicInfo +} + +interface extraInfo { + bindType: number + targetPkgName: string + appName: string +} + +const TAG: string = 'Sample_RemoteDeviceModel' +let SUBSCRIBE_ID: number = 100 + +export const BUNDLE_NAME: string = 'com.samples.avrecorder' + +export class RemoteDeviceModel { + public deviceList: Array | null = [] + public discoverList: Array = [] + private callback: () => void = () => { + } + private authCallback: () => void = () => { + } + private deviceManager: deviceManager.DeviceManager | undefined = undefined + + registerDeviceListCallback(callback: Callback) { + Logger.info(TAG, `deviceManager type =${typeof (this.deviceManager)} ,${JSON.stringify(this.deviceManager)} ,${JSON.stringify(this.deviceManager) === '{}'}`) + if (typeof (this.deviceManager) !== 'undefined') { + this.registerDeviceListCallbackImplement(callback) + return + } + Logger.info(TAG, 'deviceManager.createDeviceManager begin') + try { + let dmInstance = deviceManager.createDeviceManager(BUNDLE_NAME); + this.deviceManager = dmInstance + this.registerDeviceListCallbackImplement(callback) + Logger.info(TAG, `createDeviceManager callback returned, value= ${JSON.stringify(this.deviceManager)}`) + } catch (error) { + Logger.error(TAG, `createDeviceManager throw code:${error.code} message:${error.message}`) + } + Logger.info(TAG, 'deviceManager.createDeviceManager end') + } + + changeStateOnline(device: deviceManager.DeviceBasicInfo) { + if (this.deviceList !== null && !this.deviceList.some((existDevice) => existDevice.deviceId === device.deviceId)) { + this.deviceList![this.deviceList!.length] = device; + } + Logger.info(TAG, `online, device list= ${JSON.stringify(this.deviceList)}`); + this.callback(); + if (this.authCallback !== null) { + this.authCallback(); + this.authCallback = () => { + } + } + } + + changeStateOffline(device: deviceManager.DeviceBasicInfo) { + if (this.deviceList !== null && this.deviceList!.length > 0) { + let list: Array = []; + for (let j = 0; j < this.deviceList!.length; j++) { + if (this.deviceList![j].deviceId !== device.deviceId) { + list[j] = device; + } + } + this.deviceList = list; + } + Logger.info(TAG, `offline, updated device list=${JSON.stringify(device)}`); + this.callback(); + } + + changeState(device: deviceManager.DeviceBasicInfo, state: number) { + if (this.deviceList !== null && this.deviceList!.length <= 0) { + this.callback(); + return; + } + if (this.deviceList !== null && state === deviceManager.DeviceStateChange.AVAILABLE) { + let list: Array = new Array(); + for (let i = 0; i < this.deviceList!.length; i++) { + if (this.deviceList![i].deviceId !== device.deviceId) { + list[i] = device; + } + } + this.deviceList = list; + Logger.info(TAG, `ready, device list= ${JSON.stringify(device)}`); + this.callback(); + } else { + if (this.deviceList !== null) { + for (let j = 0; j < this.deviceList!.length; j++) { + if (this.deviceList![j].deviceId === device.deviceId) { + this.deviceList![j] = device; + break; + } + } + Logger.info(TAG, `offline, device list= ${JSON.stringify(this.deviceList)}`); + this.callback(); + } + } + } + + registerDeviceListCallbackImplement(callback: Callback) { + Logger.info(TAG, 'registerDeviceListCallback') + this.callback = callback + if (this.deviceManager === undefined) { + Logger.error(TAG, 'deviceManager has not initialized') + this.callback() + return + } + Logger.info(TAG, 'getTrustedDeviceListSync begin') + try { + let list = this.deviceManager !== undefined ? this.deviceManager.getAvailableDeviceListSync() : null; + Logger.info(TAG, `getTrustedDeviceListSync end, deviceList= ${JSON.stringify(list)}`); + if (typeof (list) !== 'undefined' && JSON.stringify(list) !== '[]') { + this.deviceList = list!; + } + Logger.info(TAG, `getTrustedDeviceListSync end, deviceList=${JSON.stringify(list)}`); + } catch (error) { + Logger.error(TAG, `getTrustedDeviceListSync throw code:${error.code} message:${error.message}`); + } + this.callback(); + Logger.info(TAG, 'callback finished'); + try { + if (this.deviceManager !== undefined) { + this.deviceManager.on('deviceStateChange', (data) => { + if (data === null) { + return + } + Logger.info(TAG, `deviceStateChange data= ${JSON.stringify(data)}`) + switch (data.action) { + case deviceManager.DeviceStateChange.AVAILABLE: + this.changeState(data.device, deviceManager.DeviceStateChange.AVAILABLE) + break + case deviceManager.DeviceStateChange.UNKNOWN: + this.changeStateOnline(data.device) + break + case deviceManager.DeviceStateChange.UNAVAILABLE: + this.changeStateOffline(data.device) + break + default: + break + } + }) + } + if (this.deviceManager !== undefined) { + this.deviceManager.on('discoverSuccess', (data) => { + if (data === null) { + return + } + this.discoverList = [] + Logger.info(TAG, `discoverSuccess data=${JSON.stringify(data)}`) + this.deviceFound(data.device) + }) + this.deviceManager.on('discoverFailure', (data) => { + Logger.info(TAG, `discoverFailure data= ${JSON.stringify(data)}`) + }) + this.deviceManager.on('serviceDie', () => { + Logger.error(TAG, 'serviceDie') + }) + } + } catch (error) { + Logger.error(TAG, `on throw code:${error.code} message:${error.message}`) + } + this.startDeviceDiscovery() + } + + deviceFound(data: deviceManager.DeviceBasicInfo) { + for (let i = 0;i < this.discoverList.length; i++) { + if (this.discoverList[i].deviceId === data.deviceId) { + Logger.info(TAG, 'device founded ignored') + return + } + } + this.discoverList[this.discoverList.length] = data + Logger.info(TAG, `deviceFound self.discoverList= ${this.discoverList}`) + this.callback() + } + + /** + * 通过SUBSCRIBE_ID搜索分布式组网内的设备 + */ + startDeviceDiscovery() { + let discoverParam: Record = { + 'discoverTargetType': 1 + }; + + let filterOptions: Record = { + 'availableStatus': 0, + }; + + Logger.info(TAG, `startDeviceDiscovery${SUBSCRIBE_ID}`); + try { + if (this.deviceManager !== undefined) { + this.deviceManager.startDiscovering(discoverParam, filterOptions) + } + } catch (error) { + Logger.error(TAG, `startDeviceDiscovery throw code:${error.code} message:${error.message}`) + } + } + + unregisterDeviceListCallback() { + Logger.info(TAG, `stopDeviceDiscovery ${SUBSCRIBE_ID}`) + if (this.deviceManager === undefined) { + return + } + if (this.deviceManager !== undefined) { + try { + Logger.info(TAG, `stopDiscovering`) + this.deviceManager.stopDiscovering(); + } catch (error) { + Logger.error(TAG, `stopDeviceDiscovery throw code:${JSON.stringify(error.code)} message:${error.message}`) + } + try { + this.deviceManager.off('deviceStateChange') + this.deviceManager.off('discoverSuccess') + this.deviceManager.off('discoverFailure') + this.deviceManager.off('serviceDie') + } catch (error) { + Logger.error(TAG, `off throw code:${error.code} message:${error.message}`) + } + } + this.deviceList = [] + this.discoverList = [] + } + + authenticateDevice(device: deviceManager.DeviceBasicInfo, callBack: Callback) { + Logger.info(TAG, `authenticateDevice ${JSON.stringify(device)}`) + Logger.info(TAG, `authenticateDevice ${device.networkId}`) + for (let i = 0; i < this.discoverList.length; i++) { + if (this.discoverList[i].deviceId !== device.deviceId) { + continue + } + if (this.deviceManager === undefined) { + return + } + try { + if (this.deviceManager !== undefined) { + this.deviceManager.bindTarget(device.deviceId, { + bindLevel: 3, + bindType: 1, + targetPkgName: BUNDLE_NAME, + appName: 'Distributed distributecalc', + }, (err, data) => { + if (err) { + Logger.error(TAG, `authenticateDevice error: ${JSON.stringify(err)}`) + this.authCallback = () => { + } + return + } + Logger.info(TAG, `authenticateDevice succeed: ${JSON.stringify(data)}`) + this.authCallback = callBack + }) + } + } catch (error) { + Logger.error(TAG, `authenticateDevice throw throw code:${error.code} message:${error.message}`) + } + } + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/recorder/VideoRecorder.ets b/test/hapAppDcameraSample/entry/src/main/ets/recorder/VideoRecorder.ets new file mode 100644 index 0000000000000000000000000000000000000000..ee7c93fe8388ccfffbb6ae17cda4f8e546ab0a9a --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/recorder/VideoRecorder.ets @@ -0,0 +1,972 @@ +/* + * Copyright (C) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { camera } from '@kit.CameraKit'; +import { media } from '@kit.MediaKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { dateTime } from '../utils/DateTimeUtils'; +import Logger from '../utils/Logger'; +import SaveCameraAsset from '../utils/SaveCameraAsset'; +import { RemoteDeviceModel } from './RemoteDeviceModel'; +import { TitleBarComponent } from '../common/TitleBarComponent' +import json from '@ohos.util.json'; +import image from '@ohos.multimedia.image'; +import fileio from '@ohos.fileio'; + +const TAG: string = 'Sample_VideoRecorder'; + +@Entry +@Component +struct VideoRecording { + @State isLand: boolean = false + @State isShow: boolean = false + @State result: string = '' + private surfaceId: string = ''; + xcomponentController: XComponentController = new XComponentController(); + private videoRecorder?: media.AVRecorder; + private cameraManager?: camera.CameraManager; + private cameras?: Array; + private cameraInput?: camera.CameraInput; + private captureSession?: camera.CaptureSession; + private previewOutput?: camera.PreviewOutput; + private videoOutput?: camera.VideoOutput; + private videoOutSurfaceId: string = ''; + private photoReceiver?: image.ImageReceiver; + private photoOutput?: camera.PhotoOutput; + private fdPath?: string = ''; + @State videoRecorderTimeText: string = '00:00'; + private seconds: number = 0; + private timer: number = 0; + private cameraIndex: number = 0; + @State videoResolution: Resolution = { frameWidth: 640, frameHeight: 480 }; + @State framerate: number = 30; // set default video framerate 30 + @State videoCodecType: string = 'video/avc'; + private recorderState: string = 'free'; + @State isStartRecording: boolean = false; + @State isPauseRecording: boolean = false; + private mSaveCameraAsset: SaveCameraAsset = new SaveCameraAsset(TAG); + private mFileAssetId?: number = 0; + private cameraOutputCapability?: camera.CameraOutputCapability; + private curVideoProfiles?: Array; + private previewProfiles?: Array; + private remoteDeviceModel: RemoteDeviceModel = new RemoteDeviceModel(); + + private avProfile: media.AVRecorderProfile = { + fileFormat: media.ContainerFormatType.CFT_MPEG_4, // set fileFormat, for video is mp4 + videoBitrate: 3000000, // set videoBitrate according to device ability + videoCodec: media.CodecMimeType.VIDEO_AVC, // set videoCodec, avc or mpeg4 can be selected + videoFrameWidth: 640, // set videoFrameWidth according to device ability + videoFrameHeight: 480, // set videoFrameHeight according to device ability + videoFrameRate: 30 // set videoFrameRate according to device ability + } + private avConfig: media.AVRecorderConfig = { + videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, + profile: this.avProfile, + url: 'fd://', + } + + aboutToAppear(): void { + Logger.info(TAG, 'aboutToAppear'); + } + + aboutToDisappear(): void { + Logger.info(TAG, 'aboutToDisappear called'); + this.releaseCamera(); + } + + onPageShow(): void { + console.info(TAG, 'onPageShow called'); + } + + onPageHide(): void { + console.info(TAG, 'onPageHide called'); + this.stopRecordingProcess(); + } + + async failureCallback(error: BusinessError): Promise { + Logger.info(TAG, 'case failureCallback called,errMessage is ', json.stringify(error)); + } + + async catchCallback(error: BusinessError): Promise { + Logger.info(TAG, 'case catchCallback called,errMessage is ', json.stringify(error)); + } + + // show recording time + getRecordTime(): void { + this.timer = setInterval(() => { + this.seconds += 1; + this.videoRecorderTimeText = dateTime(this.seconds); + }, 1000) + } + + // get recording file fd + async getFileFd(): Promise { + Logger.info(TAG, 'getFileFd called'); + this.mFileAssetId = await this.mSaveCameraAsset.createVideoFd(); + this.fdPath = 'fd://' + this.mFileAssetId.toString(); + this.avConfig.url = this.fdPath; + Logger.info(TAG, 'fdPath is: ' + this.fdPath); + Logger.info(TAG, 'getFileFd done'); + } + + async getRecordingFileFd(): Promise { + Logger.info(TAG, 'getRecordingFileFd called'); + this.mFileAssetId = await this.mSaveCameraAsset.createVideoFd(); + this.fdPath = 'fd://' + this.mFileAssetId.toString(); + this.avConfig.url = this.fdPath; + Logger.info(TAG, 'fdPath is: ' + this.fdPath); + Logger.info(TAG, 'getFileFd done'); + } + + async getImageFileFd(): Promise { + Logger.info(TAG, 'getImageFileFd called'); + this.mFileAssetId = await this.mSaveCameraAsset.createImageFd(); + this.fdPath = 'fd://' + this.mFileAssetId.toString(); + this.avConfig.url = this.fdPath; + Logger.info(TAG, 'ImageFileFd is: ' + this.fdPath); + Logger.info(TAG, 'getImageFileFd done'); + } + + // get camera ability + async initCamera(): Promise { + Logger.info(TAG, 'init camera called'); + if (this.cameraManager) { + Logger.info(TAG, 'cameraManager already exits'); + return; + } + + Logger.info(TAG, '[camera] case to get cameraManager'); + this.cameraManager = camera.getCameraManager(globalThis.abilityContext); + if (this.cameraManager) { + Logger.info(TAG, '[camera] case getCameraManager success'); + } else { + Logger.info(TAG, '[camera] case getCameraManager failed'); + return; + } + + this.cameras = this.cameraManager.getSupportedCameras(); + if (this.cameras) { + console.log(TAG, '[camera] case getCameras success, size ', this.cameras.length); + for (let i = 0; i < this.cameras.length; i++) { + let came: camera.CameraDevice = this.cameras[i]; + console.log(TAG, '[came] camera json:', JSON.stringify(came)); + if (came.connectionType == camera.ConnectionType.CAMERA_CONNECTION_REMOTE) { + this.cameraIndex = i; + this.cameraOutputCapability = this.cameraManager.getSupportedOutputCapability(came); + this.curVideoProfiles = this.cameraOutputCapability.videoProfiles; + Logger.info(TAG, 'init camera done'); + break; + } + } + } else { + Logger.info(TAG, '[camera] case getCameras failed'); + } + } + + // create camera input + async createCameraInput(): Promise { + Logger.info(TAG, 'createCameraInput called'); + if (this.cameras && this.cameras.length > 0) { + let came: camera.CameraDevice = this.cameras[this.cameraIndex]; + console.log(TAG, '[came]createCameraInput camera json:', JSON.stringify(came)); + this.cameraInput = this.cameraManager?.createCameraInput(came); + if (this.cameraInput) { + Logger.info(TAG, '[camera] case createCameraInput success'); + await this.cameraInput.open().then(() => { + Logger.info(TAG, '[camera] case cameraInput.open() success'); + }).catch((err: Error) => { + Logger.info(TAG, '[camera] cameraInput.open then.error:', json.stringify(err)); + }); + } else { + Logger.info(TAG, '[camera] case createCameraInput failed'); + return; + } + } + } + + // create camera preview + async createPreviewOutput(): Promise { + Logger.info(TAG, 'createPreviewOutput called'); + if (this.cameraOutputCapability && this.cameraManager) { + this.previewProfiles = this.cameraOutputCapability.previewProfiles; + Logger.info(TAG, '[camera] this.previewProfiles json ', json.stringify(this.previewProfiles)); + if (this.previewProfiles[0].format === camera.CameraFormat.CAMERA_FORMAT_YUV_420_SP) { + Logger.info(TAG, '[camera] case format is VIDEO_SOURCE_TYPE_SURFACE_YUV'); + this.avConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV; + } else { + Logger.info(TAG, '[camera] case format is VIDEO_SOURCE_TYPE_SURFACE_ES'); + this.avConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_ES; + } + this.previewOutput = this.cameraManager.createPreviewOutput(this.previewProfiles[0], this.surfaceId); + if (!this.previewOutput) { + Logger.info(TAG, 'create previewOutput failed!'); + } + Logger.info(TAG, 'createPreviewOutput done'); + } + } + + async createPhotoOutput() { + const photoProfile: camera.Profile = { + format: camera.CameraFormat.CAMERA_FORMAT_JPEG, + size: { + "width": 1280, + "height": 720 + } + } + if (!this.cameraManager) { + Logger.error(TAG, 'createPhotoOutput cameraManager is null') + } + if (!this.photoReceiver) { + this.photoReceiver = image.createImageReceiver(photoProfile.size.width, photoProfile.size.height, photoProfile.format, 8) + this.photoReceiver.on("imageArrival",()=>{ + this.photoReceiver?.readNextImage((err,image)=>{ + if (err || image === undefined) { + Logger.error(TAG, 'photoReceiver imageArrival on error') + return + } + image.getComponent(4, async (err, img) => { + if (err || img === undefined) { + Logger.error(TAG, 'image getComponent on error') + return + } + await this.getImageFileFd() + fileio.write(this.mFileAssetId, img.byteBuffer) + await this.closeFd() + await image.release() + Logger.info(TAG, 'photoReceiver image.getComponent save success') + }) + }) + }) + await this.photoReceiver.getReceivingSurfaceId().then((surfaceId: string) => { + this.photoOutput = this.cameraManager?.createPhotoOutput(photoProfile, surfaceId) + if (!this.photoOutput) { + Logger.error(TAG, 'cameraManager.createPhotoOutput on error') + } + Logger.info(TAG, 'cameraManager.createPhotoOutput success') + this.photoOutput?.on("captureStart", (err, captureId) => { + Logger.info(TAG, 'photoOutput.on captureStart') + }) + }).catch((err: Error) => { + Logger.error(TAG, 'photoReceiver.getReceivingSurfaceId on error:' + err) + }) + } + } + + // create camera capture session + async createCaptureSession(): Promise { + Logger.info(TAG, 'createCaptureSession called'); + if (this.cameraManager) { + this.captureSession = this.cameraManager.createCaptureSession(); + if (!this.captureSession) { + Logger.info(TAG, 'createCaptureSession failed!'); + return + } + try { + this.captureSession.beginConfig(); + this.captureSession.addInput(this.cameraInput); + } catch (e) { + Logger.error(TAG, 'case addInput error:' + json.stringify(e)); + } + try { + this.captureSession.addOutput(this.previewOutput); + } catch (e) { + Logger.error(TAG, 'case addOutput error:' + json.stringify(e)); + } + await this.captureSession.commitConfig().then(() => { + Logger.info(TAG, 'captureSession commitConfig success'); + }, this.failureCallback).catch(this.catchCallback); + } + } + + // start captureSession + async startCaptureSession(): Promise { + Logger.info(TAG, 'startCaptureSession called'); + if (!this.captureSession) { + Logger.info(TAG, 'CaptureSession does not exists!'); + return + } + await this.captureSession.start().then(() => { + Logger.info(TAG, 'case start captureSession success'); + }, this.failureCallback).catch(this.catchCallback); + } + + // remove previous videoOutput + async removeVideoOutput(): Promise { + Logger.info(TAG, 'removeVideoOutput called'); + if (this.videoOutput) { + Logger.info(TAG, 'videoOutput already exits, remove it'); + if (this.captureSession) { + this.captureSession.removeOutput(this.videoOutput); + Logger.info(TAG, 'remove videoOutput done'); + } + } + Logger.info(TAG, 'removeVideoOutput done'); + } + + // create video output + async createVideoOutput(): Promise { + Logger.info(TAG, 'createVideoOutput called'); + if (this.videoRecorder && this.curVideoProfiles && this.cameraManager) { + this.curVideoProfiles[this.cameraIndex].size.height = this.videoResolution.frameHeight; + this.curVideoProfiles[this.cameraIndex].size.width = this.videoResolution.frameWidth; + + Logger.info(TAG, '[createVideoOutput]' + this.curVideoProfiles[this.cameraIndex] + ":" + this.videoOutSurfaceId); + + this.videoOutput = this.cameraManager.createVideoOutput(this.curVideoProfiles[this.cameraIndex], this.videoOutSurfaceId); + if (!this.videoOutput) { + Logger.info(TAG, '[camera] case create videoOutPut fail!!!'); + return; + } + } else { + Logger.info(TAG, 'videoRecorder is null, createVideoOutput failed'); + return; + } + } + + // add video output into CaptureSession + async restartVideoOutput(): Promise { + Logger.info(TAG, 'restartVideoOutput called'); + if (this.captureSession) { + await this.captureSession.stop().then(() => { + Logger.info(TAG, 'case stop captureSession success'); + }, this.failureCallback).catch(this.catchCallback); + this.captureSession.beginConfig(); + await this.removeVideoOutput(); + await this.createVideoOutput(); + this.captureSession.addOutput(this.videoOutput); + await this.captureSession.commitConfig().then(() => { + Logger.info(TAG, 'case commitConfig success'); + }, this.failureCallback).catch(this.catchCallback); + await this.startCaptureSession(); + if (this.videoOutput) { + await this.videoOutput.start().then(() => { + Logger.info(TAG, '[camera] case videoOutput start success'); + }, this.failureCallback).catch(this.catchCallback); + } else { + Logger.info(TAG, 'videoOutput is null!!!'); + return; + } + } + } + + // start videoOutput + async startVideoOutput(): Promise { + Logger.info(TAG, 'startVideoOutput called'); + if (this.videoOutput) { + await this.videoOutput.start().then(() => { + Logger.info(TAG, '[camera] case videoOutput start success'); + }, this.failureCallback).catch(this.catchCallback); + } else { + Logger.info(TAG, 'videoOutput is null!!!'); + return; + } + } + + // stop videoOutput + async stopVideoOutput(): Promise { + Logger.info(TAG, 'stopVideoOutput called'); + if (this.videoOutput) { + await this.videoOutput.stop().then(() => { + Logger.info(TAG, '[camera] case videoOutput stop success'); + }, this.failureCallback).catch(this.catchCallback); + } else { + Logger.info(TAG, 'videoOutput is null!!!'); + return; + } + } + + // release camera + async releaseCameraInput(): Promise { + Logger.info(TAG, 'releaseCameraInput called'); + if (this.cameraInput) { + this.cameraInput = undefined; + } + Logger.info(TAG, 'releaseCameraInput done'); + } + + // release preview + async releasePreviewOutput(): Promise { + Logger.info(TAG, 'releasePreviewOutput called'); + if (this.previewOutput) { + await this.previewOutput.release().then(() => { + Logger.info('[camera] case main previewOutput release called'); + }, this.failureCallback).catch(this.catchCallback); + this.previewOutput = undefined; + } + Logger.info(TAG, 'releasePreviewOutput done'); + } + + // release video output + async releaseVideoOutput(): Promise { + Logger.info(TAG, 'releaseVideoOutput called'); + if (this.videoOutput) { + await this.videoOutput.release().then(() => { + Logger.info('[camera] case main videoOutput release called'); + }, this.failureCallback).catch(this.catchCallback); + this.videoOutput = undefined; + } + Logger.info(TAG, 'releaseVideoOutput done'); + } + + // stop captureSession + async stopCaptureSession(): Promise { + Logger.info(TAG, 'stopCaptureSession called'); + if (this.captureSession) { + await this.captureSession.stop().then(() => { + Logger.info('[camera] case main captureSession stop success'); + }, this.failureCallback).catch(this.catchCallback); + } + Logger.info(TAG, 'stopCaptureSession done'); + } + + // release captureSession + async releaseCaptureSession(): Promise { + Logger.info(TAG, 'releaseCaptureSession called'); + if (this.captureSession) { + await this.captureSession.release().then(() => { + Logger.info('[camera] case main captureSession release success'); + }, this.failureCallback).catch(this.catchCallback); + this.captureSession = undefined; + } + Logger.info(TAG, 'releaseCaptureSession done'); + } + + // clear camera environment + async releaseCamera(): Promise { + Logger.info(TAG, 'releaseCamera called'); + await this.stopCaptureSession(); + await this.releaseCameraInput(); + await this.releasePreviewOutput(); + await this.releaseVideoOutput(); + await this.releaseCaptureSession(); + Logger.info(TAG, 'releaseCamera done'); + } + + // set callback on + setCallback(): void { + Logger.info('case callback'); + if (this.videoRecorder) { + this.videoRecorder.on('stateChange', (state, reason) => { + Logger.info('case state has changed, new state is' + state); + switch (state) { + case 'idle': + this.recorderState = 'idle'; + break; + case 'prepared': + this.recorderState = 'prepared'; + break; + case 'started': + this.recorderState = 'started'; + this.getRecordTime(); + this.isStartRecording = true; + this.isPauseRecording = false; + break; + case 'paused': + this.recorderState = 'paused'; + clearInterval(this.timer); + this.isPauseRecording = true; + break; + case 'stopped': + this.recorderState = 'stopped'; + this.isStartRecording = false; + break; + case 'released': + this.recorderState = 'released'; + break; + case 'error': + Logger.info('case error state!!!'); + this.recorderState = 'error'; + break; + default: + Logger.info('case start is unknown'); + break; + } + }); + this.videoRecorder.on('error', (err) => { + Logger.info(TAG, 'case avRecorder.on(error) called, errMessage is ' + err.message); + }); + } + } + + async createVideoRecorder(): Promise { + await media.createAVRecorder().then((recorder) => { + Logger.info(TAG, 'case createAVRecorder called'); + if (typeof (recorder) !== 'undefined') { + this.videoRecorder = recorder; + } else { + Logger.info(TAG, 'case create avRecorder failed!!!'); + return + } + }, this.failureCallback).catch(this.catchCallback); + this.setCallback(); + } + + async prepareVideoRecorder(): Promise { + Logger.info(TAG, 'case prepareVideoRecorder in'); + if (this.videoCodecType === 'video/mpeg4') { + Logger.info(TAG, 'VIDEO_MPEG4'); + this.avConfig.profile.videoCodec = media.CodecMimeType.VIDEO_MPEG4; + } else { + Logger.info(TAG, 'VIDEO_AVC'); + this.avConfig.profile.videoCodec = media.CodecMimeType.VIDEO_AVC; + } + this.avConfig.profile.videoCodec = media.CodecMimeType.VIDEO_AVC; + console.log(TAG, this.videoResolution.frameWidth, " ", this.videoResolution.frameHeight, " ", this.framerate); + this.avConfig.profile.videoFrameHeight = 480; //this.videoResolution.frameHeight; + this.avConfig.profile.videoFrameWidth = 640; //this.videoResolution.frameWidth; + this.avConfig.profile.videoFrameRate = this.framerate; + if (this.videoRecorder) { + await this.videoRecorder.prepare(this.avConfig).then(() => { + Logger.info(TAG, 'case prepare AVRecorder called'); + }, this.failureCallback).catch(this.catchCallback); + Logger.info(TAG, 'case prepareVideoRecorder out'); + } + } + + async getInputSurface(): Promise { + Logger.info(TAG, 'case getInputSurface in'); + if (this.videoRecorder) { + await this.videoRecorder.getInputSurface().then((outPutSurface) => { + Logger.info('case getInputSurface called'); + if (!outPutSurface) { + Logger.error(TAG, 'case getInputSurface ID is none'); + return + } + this.videoOutSurfaceId = outPutSurface; + Logger.info(TAG, 'case outPutSurface surfaceID is: ' + this.videoOutSurfaceId); + }, this.failureCallback).catch(this.catchCallback); + } + Logger.info(TAG, 'case getInputSurface out'); + } + + async startVideoRecording(): Promise { + Logger.info(TAG, 'case startVideoRecording called'); + if (this.videoRecorder) { + await this.videoRecorder.start().then(() => { + Logger.info(TAG, 'case start VideoRecorder called'); + }, this.failureCallback).catch(this.catchCallback); + } + } + + async pauseVideoRecording(): Promise { + Logger.info(TAG, 'case pauseVideoRecording called'); + if (this.videoRecorder) { + await this.videoRecorder.pause().then(() => { + Logger.info(TAG, 'case pause VideoRecorder called'); + }, this.failureCallback).catch(this.catchCallback); + } + } + + async resumeVideoRecording(): Promise { + Logger.info(TAG, 'case resumeVideoRecording called'); + if (this.videoRecorder) { + await this.videoRecorder.resume().then(() => { + Logger.info(TAG, 'case resume VideoRecorder called'); + }, this.failureCallback).catch(this.catchCallback); + } + } + + async stopVideoRecording(): Promise { + Logger.info(TAG, 'case stopVideoRecording called'); + if (this.videoRecorder) { + await this.videoRecorder.stop().then(() => { + Logger.info(TAG, 'case stop VideoRecorder called'); + }, this.failureCallback).catch(this.catchCallback); + } + } + + async resetVideoRecording(): Promise { + if (this.videoRecorder) { + await this.videoRecorder.reset().then(() => { + Logger.info(TAG, 'case resetVideoRecording called'); + }, this.failureCallback).catch(this.catchCallback); + } + } + + async releaseVideoRecorder(): Promise { + if (this.videoRecorder) { + this.videoRecorder.off('stateChange'); + this.videoRecorder.off('error'); + await this.videoRecorder.release().then(() => { + Logger.info(TAG, 'case releaseVideoRecorder called'); + }, this.failureCallback).catch(this.catchCallback); + this.videoRecorder = undefined; + } + } + + // close file fd + async closeFd(): Promise { + Logger.info(TAG, 'case closeFd called'); + if (this.mSaveCameraAsset) { + await this.mSaveCameraAsset.closeVideoFile(); + this.mFileAssetId = undefined; + this.fdPath = undefined; + Logger.info(TAG, 'case closeFd done'); + } + } + + // init camera + async enterInit(): Promise { + Logger.info(TAG, 'enterInit called'); + await this.initCamera(); // 获取设备相机信息 + await this.createCameraInput(); // 打开相机 + Logger.info(TAG, 'enterInit createPreviewOutput'); + await this.createPreviewOutput(); // 预览流 + // await this.createPhotoOutput(); // 拍照流 + await this.createCaptureSession(); // 会话,保存一次相机运行需要的所有资源,并向相机设备申请完成相机功能 + await this.startCaptureSession(); // 开启会话 + Logger.info(TAG, 'end enterInit'); + } + + // start button process + async startRecordingProcess(): Promise { + Logger.info(TAG, 'startRecording called'); + await this.createVideoRecorder(); + await this.getFileFd(); + await this.prepareVideoRecorder(); + await this.getInputSurface(); + await this.restartVideoOutput(); + await this.startVideoRecording(); + Logger.info(TAG, 'startRecording done'); + } + + // pause button process + async pauseRecordingProcess(): Promise { + Logger.info(TAG, 'pauseRecording called'); + if (this.recorderState === 'started') { + Logger.info(TAG, 'current state is started, to pause'); + await this.pauseVideoRecording(); + await this.stopVideoOutput(); + } + Logger.info(TAG, 'pauseRecording done'); + } + + // resume button process + async resumeRecordingProcess(): Promise { + Logger.info(TAG, 'resumeRecording called'); + if (this.recorderState === 'paused') { + Logger.info(TAG, 'current state is paused, to resume'); + await this.startVideoOutput(); + await this.resumeVideoRecording(); + } + Logger.info(TAG, 'resumeRecording done'); + } + + // stop button process + async stopRecordingProcess(): Promise { + Logger.info(TAG, 'stopRecording called'); + if (this.recorderState === 'started' || this.recorderState === 'paused') { + await this.stopVideoRecording(); + } + await this.resetVideoRecording(); + await this.releaseVideoRecorder(); + await this.stopVideoOutput(); + this.videoOutput = undefined; + await this.closeFd(); + clearInterval(this.timer); + this.isStartRecording = false; + this.isPauseRecording = false; + this.seconds = 0; + this.videoRecorderTimeText = '00:00'; + Logger.info(TAG, 'stopRecording done'); + } + + startAbilityCallBack = (key: string) => { + Logger.info(TAG, `startAbilityCallBack ${key}`) + } + onInputValue = (value: string) => { + } + + build() { + Column() { + Row() { + Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween }) { + TitleBarComponent({ + isLand: this.isLand, + startAbilityCallBack: this.startAbilityCallBack, + remoteDeviceModel: this.remoteDeviceModel, + isShow: this.isShow + }) + Button("connect remote") + .onClick(() => { + this.enterInit(); + }) + } + } + + Column() { + Row() { + Stack({ alignContent: Alignment.Center }) { + XComponent({ + id: 'xcomponent1', + type: 'surface', + controller: this.xcomponentController + }) + .onLoad(() => { + this.xcomponentController.setXComponentSurfaceSize({ surfaceWidth: 640, surfaceHeight: 480 }) + this.surfaceId = this.xcomponentController.getXComponentSurfaceId() + Logger.info(TAG, '[VideoRecorder] surfaceId: ' + this.surfaceId) + Logger.info(TAG, 'XComponent1 loaded'); + }) + .width('100%').height('100%') + Text(this.videoRecorderTimeText) + .fontFamily('HarmonyHeiTi-Light') + .width(70) + .height(40) + .fontSize(27) + .fontColor(Color.Red) + .margin({ + left: 155, + top: 18, + right: 135, + bottom: 707 + }) + .visibility(this.isStartRecording ? Visibility.Visible : Visibility.Hidden) + Image($r('app.media.take_video_normal')) + .width(86) + .height(86) + .margin({ + left: 132, + top: 612, + right: 132, + bottom: 72 + }) + .onClick(() => this.startRecordingProcess()) + .id('videoStart') + .visibility(this.isStartRecording ? Visibility.Hidden : Visibility.Visible) + Image($r('app.media.ic_circle_open')) + .width(120) + .height(56) + .margin({ + left: 120, + top: 632, + right: 120, + bottom: 92 + }) + .visibility(this.isStartRecording ? Visibility.Visible : Visibility.Hidden) + Image($r('app.media.ic_stop')) + .width(16) + .height(16) + .margin({ + left: 146, + top: 652, + right: 198, + bottom: 112 + }) + .onClick(() => this.stopRecordingProcess()) + .id('videoStop') + .visibility(this.isStartRecording ? Visibility.Visible : Visibility.Hidden) + Image($r('app.media.ic_pause')) + .width(14) + .height(15) + .margin({ + left: 200, + top: 652, + right: 146, + bottom: 113 + }) + .onClick(() => this.pauseRecordingProcess()) + .id('videoPause') + .visibility(this.isStartRecording && !this.isPauseRecording ? Visibility.Visible : Visibility.Hidden) + Image($r('app.media.ic_continue')) + .width(16) + .height(16) + .margin({ + left: 198, + top: 651, + right: 144, + bottom: 111 + }) + .onClick(() => this.resumeRecordingProcess()) + .id('videoResume') + .visibility(this.isStartRecording && this.isPauseRecording ? Visibility.Visible : Visibility.Hidden) + }.width('100%').height('100%') + }.width('100%').height('88%') + } + } + } + + onCancel() { + Logger.info(TAG, 'Callback when the cancel button is clicked') + } + + onAccept() { + Logger.info(TAG, 'Callback when the confirm button is clicked') + } + + existApp() { + Logger.info(TAG, 'Click the callback in the blank area') + } + + settingDialog: CustomDialogController = new CustomDialogController({ + builder: CustomDialogSetting({ + cancel: this.onCancel, + confirm: this.onAccept, + videoResolution: $videoResolution, + videoFrameRate: $framerate, + videoCodec: $videoCodecType, + }), + cancel: this.existApp, + autoCancel: false, + alignment: DialogAlignment.Bottom, + customStyle: true + }) +} + +class Resolution { + public frameWidth: number = 0 + public frameHeight: number = 0 +} + +class VideoResolution { + public itemValue: string = '' + public value: Resolution = { frameWidth: 0, frameHeight: 0 } +} + +class VideoFrameRate { + public itemValue: string = '' + public value: number = 0 +} + +class VideoCodec { + public itemValue: string = '' + public value: string = '' +} + +@CustomDialog +struct CustomDialogSetting { + @Link videoResolution: Resolution; + @Link videoFrameRate: number; + @Link videoCodec: string; + controller: CustomDialogController; + cancel?: () => void; + confirm?: () => void; + @State currentVideoResolution: Resolution = { frameWidth: 640, frameHeight: 480 }; + @State currentVideoResolutionText: string = '[16:9]1080p'; + @State currentVideoFramerate: number = 30; + @State currentVideoCodec: string = 'video/avc'; + private initVideoResolution: Resolution = this.videoResolution; + private initVideoFramerate: number = this.videoFrameRate; + private initVideoCodec: string = 'video/avc'; + @State videoResolutionList: Array = [ + { itemValue: '16:9 (720p)', value: { frameWidth: 1280, frameHeight: 720 } }, + { itemValue: '16:9 (1080p)', value: { frameWidth: 640, frameHeight: 480 } }, + ]; + @State videoFrameRateList: Array = [ + { itemValue: '30fps', value: 30 }, + ]; + @State videoCodecList: Array = [ + { itemValue: 'video/avc', value: 'video/avc' }, + { itemValue: 'video/mpeg4', value: 'video/mpeg4' }, + ]; + + build() { + Column() { + Column() { + Text($r('app.string.video_parameter')) + .fontFamily('HarmonyHeiTi-Medium') + .fontSize(20) + .width(288) + .height(26) + .margin({ left: 24, top: 16, right: 24 }) + Column() { + List({ space: 10 }) { + ForEach(this.videoResolutionList, (item: VideoResolution, index) => { + ListItem() { + Row() { + Text($r('app.string.video_resolution')) + .fontSize(16) + Text(item.itemValue.toString()) + .fontSize(16) + .width(160) + .fontFamily('HarmonyHeiTi-Medium') + Radio({ value: item.value.toString(), group: 'radioGroup' }) + .checked(item.value.frameWidth == this.initVideoResolution.frameWidth) + .height(24) + .onChange((isChecked: boolean) => { + if (isChecked) { + Logger.info(TAG, item.itemValue + ' resolution is clicked') + this.currentVideoResolution = item.value; + this.currentVideoResolutionText = item.itemValue; + } + }) + }.margin({ left: 0, right: 39 }) + } + }) + }.listDirection(Axis.Vertical) + .divider({ + strokeWidth: 0.5, + color: '#EEEEEE', + startMargin: 0, + endMargin: 0 + }) + }.margin({ left: 24, right: 24, top: 16 }) + }.alignItems(HorizontalAlign.Start) + + Row() { + Button($r('app.string.button_cancel')) + .onClick(() => { + this.videoResolution = this.initVideoResolution + this.videoFrameRate = this.initVideoFramerate + this.videoCodec = this.initVideoCodec + this.controller.close() + if (this.cancel) { + this.cancel() + } + }) + .backgroundColor($r('app.color.button_background')) + .fontColor($r('app.color.button_color')) + .fontFamily('HarmonyHeiTi-Medium') + .fontSize(16) + .id('videoCancel') + .layoutWeight(1) + Divider() + .vertical(true) + .height(24) + .color($r('app.color.divider_color')) + .opacity(0.6) + .margin({ left: 8, right: 8 }) + Button($r('app.string.button_confirm')) + .onClick(() => { + this.videoResolution = this.currentVideoResolution + this.videoFrameRate = this.currentVideoFramerate + this.videoCodec = this.currentVideoCodec + this.controller.close() + if (this.confirm) { + this.confirm() + } + }) + .backgroundColor($r('app.color.button_background')) + .fontColor($r('app.color.button_color')) + .fontFamily('HarmonyHeiTi-Medium') + .fontSize(16) + .id('videoConfirm') + .layoutWeight(1) + } + .width(300) + .height(40) + .margin({ + left: 24, + right: 24, + top: 12, + bottom: 16 + }) + } + .margin({ left: 12, right: 12, bottom: 12 }) + .backgroundColor($r('app.color.button_background')) + .borderRadius(32) + .alignItems(HorizontalAlign.Center) + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/utils/DateTimeUtils.ets b/test/hapAppDcameraSample/entry/src/main/ets/utils/DateTimeUtils.ets new file mode 100644 index 0000000000000000000000000000000000000000..76c5c325f2e7a84a5a3bc1aa8a61ada0f7d17664 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/utils/DateTimeUtils.ets @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export default class DateTimeUtil { + getTime(): string { + const DATETIME = new Date(); + return this.concatTime(DATETIME.getHours(), DATETIME.getMinutes(), DATETIME.getSeconds()) + } + + getDate(): string { + const DATETIME = new Date(); + return this.concatDate(DATETIME.getFullYear(), DATETIME.getMonth() + 1, DATETIME.getDate()) + } + + fill(value: number): string { + return (value > 9 ? '' : '0') + value; + } + + concatDate(year: number, month: number, date: number): string { + return `${year}${month}${date}`; + } + + concatTime(hour: number, minute: number, second: number): string { + return `${this.fill(hour)}${this.fill(minute)}${this.fill(second)}`; + } +} + +export function getShownTimer(ms: number): string { + let seconds: number = Math.round(ms / 1000); + let sec: number = seconds % 60; + let min: number = (seconds - sec) / 60; + if (sec < 10) { + sec = 0 + sec; + } + if (min < 10) { + min = 0 + min; + } + return min + ':' + sec; +} + +export function dateTime(t: number): string { + let minute: number = Math.floor(t / 60) % 60 + let m = minute < 10 ? '0' + minute : minute + let second: number = t % 60 + let s = second < 10 ? '0' + second : second + return m + ':' + s; +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/utils/ImageList.ets b/test/hapAppDcameraSample/entry/src/main/ets/utils/ImageList.ets new file mode 100644 index 0000000000000000000000000000000000000000..7471f04073a8c66f3f61a281181b81f298ef51b3 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/utils/ImageList.ets @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export class ImageList { + image: Resource + value: string + + constructor(image: Resource, value: string) { + this.image = image + this.value = value + } +} + +export function obtainImgVertical(): Record[] { + let list: Record[] = + [ + { 'image': $r('app.media.ic_cal_seven'), 'value': '7' }, + { 'image': $r('app.media.ic_cal_eight'), 'value': '8' }, + { 'image': $r('app.media.ic_cal_nine'), 'value': '9' }, + { 'image': $r('app.media.ic_cal_four'), 'value': '4' }, + { 'image': $r('app.media.ic_cal_five'), 'value': '5' }, + { 'image': $r('app.media.ic_cal_six'), 'value': '6' }, + { 'image': $r('app.media.ic_cal_one'), 'value': '1' }, + { 'image': $r('app.media.ic_cal_two'), 'value': '2' }, + { 'image': $r('app.media.ic_cal_three'), 'value': '3' }, + { 'image': $r('app.media.ic_cal_zero'), 'value': '0' }, + { 'image': $r('app.media.ic_cal_point'), 'value': '.' }, + ] + return list +} + +export function obtainImgV(): Record[] { + let list: Record[] = + [ + { 'image': $r('app.media.ic_cal_delete'), 'value': 'D' }, + { 'image': $r('app.media.ic_cal_delete_c'), 'value': 'C' }, + { 'image': $r('app.media.ic_cal_equal'), 'value': '=' } + ]; + return list; +} + +export function obtainImgVs(): Record[] { + let list: Record[] = + [ + { 'image': $r('app.media.ic_cal_devide'), 'value': '/' }, + { 'image': $r('app.media.ic_cal_multiply'), 'value': '*' }, + { 'image': $r('app.media.ic_cal_minus'), 'value': '-' }, + { 'image': $r('app.media.ic_cal_plus'), 'value': '+' } + ]; + return list; +} + +export function obtainImgLevel(): Record[] { + let list: Record[] = [ + { 'image': $r('app.media.ic_cal_seven'), 'value': '7' }, + { 'image': $r('app.media.ic_cal_eight'), 'value': '8' }, + { 'image': $r('app.media.ic_cal_nine'), 'value': '9' }, + { 'image': $r('app.media.ic_cal_devide'), 'value': '/' }, + { 'image': $r('app.media.ic_cal_four'), 'value': '4' }, + { 'image': $r('app.media.ic_cal_five'), 'value': '5' }, + { 'image': $r('app.media.ic_cal_six'), 'value': '6' }, + { 'image': $r('app.media.ic_cal_multiply'), 'value': '*' }, + { 'image': $r('app.media.ic_cal_one'), 'value': '1' }, + { 'image': $r('app.media.ic_cal_two'), 'value': '2' }, + { 'image': $r('app.media.ic_cal_three'), 'value': '3' }, + { 'image': $r('app.media.ic_cal_minus'), 'value': '-' }, + { 'image': $r('app.media.ic_cal_zero'), 'value': '0' }, + { 'image': $r('app.media.ic_cal_point'), 'value': '.' }, + { 'image': $r('app.media.ic_cal_plus'), 'value': '+' } + ] + return list +} + +export function obtainImg(): Record[] { + let list: Record[] = [ + { 'image': $r('app.media.ic_cal_delete'), 'value': 'D' }, + { 'image': $r('app.media.ic_cal_delete_c'), 'value': 'C' }, + { 'image': $r('app.media.ic_cal_equal'), 'value': '=' } + ]; + return list; +} + +export function obtainImgL(): Record[] { + let list: Record[] = [ + { 'image': $r('app.media.ic_cal_zero'), 'value': '0' }, + { 'image': $r('app.media.ic_cal_point'), 'value': '.' }, + { 'image': $r('app.media.ic_cal_plus'), 'value': '+' } + ] + return list +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/utils/Logger.ts b/test/hapAppDcameraSample/entry/src/main/ets/utils/Logger.ts new file mode 100644 index 0000000000000000000000000000000000000000..1c03ba768c0d934308d4b8282207bbb18131d4a9 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/utils/Logger.ts @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import hilog from '@ohos.hilog'; + +class Logger { + private domain: number; + private prefix: string; + private format: string = '%{public}s, %{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + this.domain = 0xFF00; + } + + debug(...args: string[]): void { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]): void { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]): void { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]): void { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('AVRecorderSample'); \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/ets/utils/SaveCameraAsset.ets b/test/hapAppDcameraSample/entry/src/main/ets/utils/SaveCameraAsset.ets new file mode 100644 index 0000000000000000000000000000000000000000..ee3d871d4074a8386e593f8d868f5442b3d88468 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/ets/utils/SaveCameraAsset.ets @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2023-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { common } from '@kit.AbilityKit'; +import { fileIo as fs } from '@kit.CoreFileKit'; +import DateTimeUtil from './DateTimeUtils'; +import Logger from './Logger'; +import { photoAccessHelper } from '@kit.MediaLibraryKit'; +import { dataSharePredicates } from '@kit.ArkData'; + +export default class SaveCameraAsset { + private tag: string + + constructor(tag: string) { + this.tag = tag; + } + + private context = getContext(this) as common.UIAbilityContext; + private lastSaveTime: string = ''; + private saveIndex: number = 0; + public VideoPrepareFile?: fs.File; + public AudioPrepareFile?: fs.File; + public ImagePrepareFile?: fs.File; + + public async createImageFd() { + Logger.info(this.tag, 'get Image File Fd'); + const mDateTimeUtil = new DateTimeUtil(); + const displayName = this.checkName(`REC_${mDateTimeUtil.getDate()}_${mDateTimeUtil.getTime()}`) + '.jpg'; + Logger.info(this.tag, 'get Image display name is: ' + displayName); + this.ImagePrepareFile = fs.openSync(this.context.filesDir + '/' + displayName, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); + let fdNumber: number = this.ImagePrepareFile.fd; + Logger.info(this.tag, 'get Image File fd is: ' + JSON.stringify(fdNumber)); + return fdNumber; + } + + public async closeImageFile() { + if (this.ImagePrepareFile) { + await fs.close(this.ImagePrepareFile); + Logger.info(this.tag, 'close Image File end'); + } + } + + public async createVideoFd() { + // const context = getContext(this); + // let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); + // let albumPredicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates(); + // albumPredicates.equalTo(photoAccessHelper.AlbumKeys.ALBUM_NAME, 'albumName'); + // let albumFetchOptions: photoAccessHelper.FetchOptions = { + // fetchColumns: [], + // predicates: albumPredicates + // }; + // + // let photoPredicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates(); + // let photoFetchOptions: photoAccessHelper.FetchOptions = { + // fetchColumns: [], + // predicates: photoPredicates + // }; + // + // let photoFetchResult: photoAccessHelper.FetchResult + // let albumFetchResult: photoAccessHelper.FetchResult + // + // try { + // photoFetchResult = await phAccessHelper.getAssets(photoFetchOptions); + // let photoAsset: photoAccessHelper.PhotoAsset = await photoFetchResult.getFirstObject(); + // console.info('getAssets successfully, albumName: ' + photoAsset.displayName); + // + // let uri: string = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.VIDEO, "mp4", (err, uri) => { + // + // }) + // + // albumFetchResult = + // await phAccessHelper.getAlbums(photoAccessHelper.AlbumType.USER, photoAccessHelper.AlbumSubtype.USER_GENERIC, + // albumFetchOptions); + // let album: photoAccessHelper.Album = await albumFetchResult.getFirstObject(); + // console.info('getAlbums successfully, albumName: ' + album.albumName); + // let albumChangeRequest: photoAccessHelper.MediaAlbumChangeRequest = + // new photoAccessHelper.MediaAlbumChangeRequest(album); + // albumChangeRequest.addAssets([photoAsset]); + // await phAccessHelper.applyChanges(albumChangeRequest); + // console.info('succeed to add ' + photoAsset.displayName + ' to ' + album.albumName); + // + // } catch (err) { + // console.error('addAssets failed with err: ' + err); + // } finally { + // photoFetchResult!.close(); + // albumFetchResult!.close(); + // } + + Logger.info(this.tag, 'get Recorder File Fd'); + const mDateTimeUtil = new DateTimeUtil(); + const displayName = this.checkName(`REC_${mDateTimeUtil.getDate()}_${mDateTimeUtil.getTime()}`) + '.mp4'; + Logger.info(this.tag, 'get Recorder display name is: ' + displayName); + this.VideoPrepareFile = fs.openSync(this.context.filesDir + '/' + displayName, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); + let fdNumber: number = this.VideoPrepareFile.fd; + Logger.info(this.tag, 'get Recorder File fd is: ' + JSON.stringify(fdNumber)); + return fdNumber; + } + + // public async createVideoFd() { + // Logger.info(this.tag, 'get Recorder File Fd'); + // const mDateTimeUtil = new DateTimeUtil(); + // const displayName = this.checkName(`REC_${mDateTimeUtil.getDate()}_${mDateTimeUtil.getTime()}`) + '.mp4'; + // Logger.info(this.tag, 'get Recorder display name is: ' + displayName); + // this.VideoPrepareFile = fs.openSync(this.context.filesDir + '/' + displayName, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); + // let fdNumber: number = this.VideoPrepareFile.fd; + // Logger.info(this.tag, 'get Recorder File fd is: ' + JSON.stringify(fdNumber)); + // return fdNumber; + // } + + public async closeVideoFile() { + if (this.VideoPrepareFile) { + await fs.close(this.VideoPrepareFile); + Logger.info(this.tag, 'close Video File end'); + } + } + + public async createAudioFd() { + Logger.info(this.tag, 'get Recorder File Fd'); + const mDateTimeUtil = new DateTimeUtil(); + const displayName = this.checkName(`REC_${mDateTimeUtil.getDate()}_${mDateTimeUtil.getTime()}`) + '.wav'; + Logger.info(this.tag, 'get Recorder display name is: ' + displayName); + this.AudioPrepareFile = fs.openSync(this.context.filesDir + '/' + displayName, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); + let fdNumber: number = this.AudioPrepareFile.fd; + Logger.info(this.tag, 'get Recorder File fd is: ' + JSON.stringify(fdNumber)); + return fdNumber; + } + + public async closeAudioFile() { + if (this.AudioPrepareFile) { + await fs.close(this.AudioPrepareFile); + Logger.info(this.tag, 'close Audio File end'); + } + } + + private checkName(name: string): string { + if (this.lastSaveTime == name) { + this.saveIndex += 1; + return `${name}_${this.saveIndex}` + } + this.lastSaveTime = name; + this.saveIndex = 0; + Logger.info(this.tag, 'get Recorder File name is: ' + name); + return name; + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/module.json5 b/test/hapAppDcameraSample/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..75b6546c11eae6e19dd4296e58478d077683a704 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/module.json5 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ts", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "requestPermissions": [ + { + "name": 'ohos.permission.DISTRIBUTED_DATASYNC', + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } + }, + { + "name": 'ohos.permission.USE_BLUETOOTH', + "reason": '$string:reason' + }, + { + "name": 'ohos.permission.DISCOVER_BLUETOOTH', + "reason": '$string:reason' + }, + { + "name": "ohos.permission.MEDIA_LOCATION", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } + }, + { + "name": "ohos.permission.READ_MEDIA", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } + }, + { + "name": "ohos.permission.WRITE_MEDIA", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } + }, + { + "name": "ohos.permission.CAMERA", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } + }, + { + "name": "ohos.permission.MICROPHONE", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ], + } + ], + "deliveryWithInstall": true + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/element/color.json b/test/hapAppDcameraSample/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..0d98b5c17780f121191f2768bdf0cd0bc6e9b9e7 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/element/color.json @@ -0,0 +1,28 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + }, + { + "name": "button_background", + "value": "#FFFFFF" + }, + { + "name": "homepage_background", + "value": "#F1F3F5" + }, + { + "name": "title_color", + "value": "#000000" + }, + { + "name": "button_color", + "value": "#007DFF" + }, + { + "name": "divider_color", + "value": "#182431" + } + ] +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/element/string.json b/test/hapAppDcameraSample/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..81a79fefaf43bb5907e974fcf86bccfd8c552a3d --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/element/string.json @@ -0,0 +1,84 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "This module template implements List functions." + }, + { + "name": "ability_desc", + "value": "This ability loads ListPage" + }, + { + "name": "ability_label", + "value": "List Ability" + }, + { + "name": "page_title", + "value": "Title" + }, + { + "name": "page_title_video", + "value": "VideoRecorder" + }, + { + "name": "page_title_audio", + "value": "AudioRecorder" + }, + { + "name": "button_confirm", + "value": "confirm" + }, + { + "name": "button_cancel", + "value": "cancel" + }, + { + "name": "audio_parameter", + "value": "Select audio samplerate" + }, + { + "name": "audio_samplerate", + "value": "audio samplerate: " + }, + { + "name": "video_parameter", + "value": "Select video resolution" + }, + { + "name": "video_resolution", + "value": "video resolution: " + }, + { + "name": "reason", + "value": "Permission" + }, + { + "name": "choiceDevice", + "value": "Choice Device" + }, + { + "name": "cancel", + "value": "Cancel" + }, + { + "name": "distributed_calculator", + "value": "distributed calculator" + }, + { + "name": "distributed_permission", + "value": "Allow data exchange between different devices" + }, + { + "name": "localhost", + "value": "localhost" + }, + { + "name": "EntryAbility_desc", + "value": "EntryAbility" + }, + { + "name": "EntryAbility_label", + "value": "EntryAbility" + } + ] +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/background.png b/test/hapAppDcameraSample/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/test/hapAppDcameraSample/entry/src/main/resources/base/media/background.png differ diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/checked.png b/test/hapAppDcameraSample/entry/src/main/resources/base/media/checked.png new file mode 100644 index 0000000000000000000000000000000000000000..a77ded514ac884365ec515801bb34c68e6e5b7f8 Binary files /dev/null and b/test/hapAppDcameraSample/entry/src/main/resources/base/media/checked.png differ diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/equal.png b/test/hapAppDcameraSample/entry/src/main/resources/base/media/equal.png new file mode 100644 index 0000000000000000000000000000000000000000..9fc25a3e16bdde93933d4bb2571631e1d382f1fb Binary files /dev/null and b/test/hapAppDcameraSample/entry/src/main/resources/base/media/equal.png differ diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/foreground.png b/test/hapAppDcameraSample/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/test/hapAppDcameraSample/entry/src/main/resources/base/media/foreground.png differ diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_back.png b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_back.png new file mode 100644 index 0000000000000000000000000000000000000000..4a269a11a6eca005d2eabb957992297446c858db Binary files /dev/null and b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_back.png differ diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_delete.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_delete.svg new file mode 100644 index 0000000000000000000000000000000000000000..34cd7762965b6bdbd920ccd6bc1cd17028aabc11 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_delete.svg @@ -0,0 +1,12 @@ + + + ic_cal_delete + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_delete_c.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_delete_c.svg new file mode 100644 index 0000000000000000000000000000000000000000..d251a289d7710cadb6df00b1d9e6cf9b9dbd22f2 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_delete_c.svg @@ -0,0 +1,12 @@ + + + ic_cal_delete_c + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_devide.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_devide.svg new file mode 100644 index 0000000000000000000000000000000000000000..6a24531c8ea11291ed310d302c711e61d63d2d7f --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_devide.svg @@ -0,0 +1,12 @@ + + + ic_cal_devide + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_eight.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_eight.svg new file mode 100644 index 0000000000000000000000000000000000000000..9da3b65c0a15ae6036592c86466724b8314b0f5d --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_eight.svg @@ -0,0 +1,12 @@ + + + ic_cal_eight + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_equal.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_equal.svg new file mode 100644 index 0000000000000000000000000000000000000000..8ff483b2e53c808b9f485ee2f6f99084f90b7ffc --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_equal.svg @@ -0,0 +1,26 @@ + + + ic_cal_equal + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_five.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_five.svg new file mode 100644 index 0000000000000000000000000000000000000000..b41c8d2b06f8997968a6babeedfc49474f78f7f5 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_five.svg @@ -0,0 +1,12 @@ + + + ic_cal_five + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_four.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_four.svg new file mode 100644 index 0000000000000000000000000000000000000000..32d0e1ad276595c5513075198fa76cefc2ce7b09 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_four.svg @@ -0,0 +1,12 @@ + + + ic_cal_four + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_minus.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_minus.svg new file mode 100644 index 0000000000000000000000000000000000000000..08afe0f7bdf2e32bdde263c3e78e2a14c9d88d50 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_minus.svg @@ -0,0 +1,12 @@ + + + ic_cal_minus + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_multiply.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_multiply.svg new file mode 100644 index 0000000000000000000000000000000000000000..3899760bc2aea51d0b0bfa3e1c203339e8436563 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_multiply.svg @@ -0,0 +1,12 @@ + + + ic_cal_multiply + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_nine.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_nine.svg new file mode 100644 index 0000000000000000000000000000000000000000..9b642e7cddfd06e2433f4042cc74d9c78da1cbce --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_nine.svg @@ -0,0 +1,12 @@ + + + ic_cal_nine + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_one.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_one.svg new file mode 100644 index 0000000000000000000000000000000000000000..408b1944bd9b1609c2dbe75c2b030f288fc40107 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_one.svg @@ -0,0 +1,12 @@ + + + 1 + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_percent.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_percent.svg new file mode 100644 index 0000000000000000000000000000000000000000..745fc44f43cd336c31981940f496a3091eda23a9 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_percent.svg @@ -0,0 +1,12 @@ + + + ic_cal_percent + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_plus.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_plus.svg new file mode 100644 index 0000000000000000000000000000000000000000..62e40d702a8342b46eb7c0864ef7009bf9138632 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_plus.svg @@ -0,0 +1,15 @@ + + + ic_cal_plus + + + + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_point.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_point.svg new file mode 100644 index 0000000000000000000000000000000000000000..62a5b528d3ede78e4687d047302abae0cfd8c783 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_point.svg @@ -0,0 +1,12 @@ + + + ic_cal_point + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_seven.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_seven.svg new file mode 100644 index 0000000000000000000000000000000000000000..cd41701f737a92a6df52eb3b8058dab7e3464bc4 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_seven.svg @@ -0,0 +1,12 @@ + + + ic_cal_seven + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_six.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_six.svg new file mode 100644 index 0000000000000000000000000000000000000000..1831a2b9922c7162fa8f799e973a076731625b2b --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_six.svg @@ -0,0 +1,12 @@ + + + ic_cal_six + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_three.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_three.svg new file mode 100644 index 0000000000000000000000000000000000000000..26ab9bd51fbe9eb86e166cb7dca0ca2c7c3c2c67 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_three.svg @@ -0,0 +1,12 @@ + + + ic_cal_three + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_two.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_two.svg new file mode 100644 index 0000000000000000000000000000000000000000..314d1fe4974d0bd6c8dc5b8cfbcad1b75e09264e --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_two.svg @@ -0,0 +1,12 @@ + + + ic_cal_two + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_zero.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_zero.svg new file mode 100644 index 0000000000000000000000000000000000000000..7c2816caf1386519bbf2f31647931b066a0410b3 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_zero.svg @@ -0,0 +1,12 @@ + + + ic_cal_zero + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_zero_short.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_zero_short.svg new file mode 100644 index 0000000000000000000000000000000000000000..5dc9ebe8e7ae9d0df8cc5e247f754da3f1d916aa --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_cal_zero_short.svg @@ -0,0 +1,12 @@ + + + ic_cal_zero_short + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_circle_open.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_circle_open.svg new file mode 100644 index 0000000000000000000000000000000000000000..790e8a5b99436437f89dd3385da5eefb92b30103 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_circle_open.svg @@ -0,0 +1,7 @@ + + + ic_circle_open + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_continue.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_continue.svg new file mode 100644 index 0000000000000000000000000000000000000000..a5b250f868023c850e03bc6df0bea32596863f25 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_continue.svg @@ -0,0 +1,7 @@ + + + ic_continue + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_hop.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_hop.svg new file mode 100644 index 0000000000000000000000000000000000000000..bc30a02a1d3ccffbad1b3670507e8c849a073395 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_hop.svg @@ -0,0 +1,18 @@ + + + icon-hop + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_hop_normal.png b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_hop_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..435ec58bbde7bc034fe558dc890af0b653ae2e2f Binary files /dev/null and b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_hop_normal.png differ diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_hop_normal1.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_hop_normal1.svg new file mode 100644 index 0000000000000000000000000000000000000000..e104151dd4a2517dc6041d37e91901f13c8edd46 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_hop_normal1.svg @@ -0,0 +1,18 @@ + + + icon-hop + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_pause.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_pause.svg new file mode 100644 index 0000000000000000000000000000000000000000..b56bd247421f21b109ce95dd3ea2c7c8f464d522 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_pause.svg @@ -0,0 +1,7 @@ + + + ic_pause + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_red_circle.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_red_circle.svg new file mode 100644 index 0000000000000000000000000000000000000000..e678e9735e410638dc03f10692ae5f817af51d80 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_red_circle.svg @@ -0,0 +1,13 @@ + + + ic_red_circle + + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_setting.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_setting.svg new file mode 100644 index 0000000000000000000000000000000000000000..be1604576c904ca6d3ccee9a88c9267e786da6f1 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_setting.svg @@ -0,0 +1,14 @@ + + + ic_setting + + + + + + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_small_pause.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_small_pause.svg new file mode 100644 index 0000000000000000000000000000000000000000..1508bfaacba8902244dc50997cf1e550d9b8a15f --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_small_pause.svg @@ -0,0 +1,9 @@ + + + ic_small_pause + + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_stop.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_stop.svg new file mode 100644 index 0000000000000000000000000000000000000000..cdbf8a235afe133b20e632ea953d859398af6c0d --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/ic_stop.svg @@ -0,0 +1,7 @@ + + + ic_stop + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/icon.png b/test/hapAppDcameraSample/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/test/hapAppDcameraSample/entry/src/main/resources/base/media/icon.png differ diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/layered_image.json b/test/hapAppDcameraSample/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/startIcon.png b/test/hapAppDcameraSample/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/test/hapAppDcameraSample/entry/src/main/resources/base/media/startIcon.png differ diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/take_video_normal.svg b/test/hapAppDcameraSample/entry/src/main/resources/base/media/take_video_normal.svg new file mode 100644 index 0000000000000000000000000000000000000000..7904aedd2c5ceadac4e68487d6f75a886a3e5683 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/media/take_video_normal.svg @@ -0,0 +1,10 @@ + + + + ic/camera/shutter/take_video_normal + Created with Sketch. + + + + + \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/media/uncheck.png b/test/hapAppDcameraSample/entry/src/main/resources/base/media/uncheck.png new file mode 100644 index 0000000000000000000000000000000000000000..cba71b7ec168e67e261151ee8cb9e950f53e7cbb Binary files /dev/null and b/test/hapAppDcameraSample/entry/src/main/resources/base/media/uncheck.png differ diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/profile/backup_config.json b/test/hapAppDcameraSample/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/entry/src/main/resources/base/profile/main_pages.json b/test/hapAppDcameraSample/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..8f0137aa7e56367a33402a5b5ffcff2b9f2356b2 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,7 @@ +{ + "src": [ + "pages/ListPage", + "recorder/AudioRecorder", + "recorder/VideoRecorder" + ] +} diff --git a/test/hapAppDcameraSample/entry/src/main/resources/dark/element/color.json b/test/hapAppDcameraSample/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/test/hapAppDcameraSample/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#000000" + } + ] +} \ No newline at end of file diff --git a/test/hapAppDcameraSample/hvigor/hvigor-config.json5 b/test/hapAppDcameraSample/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5282eefe0593f56f8ddabfbf05783dc836c3c8b4 --- /dev/null +++ b/test/hapAppDcameraSample/hvigor/hvigor-config.json5 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "modelVersion": "5.0.1", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/test/hapAppDcameraSample/hvigorfile.ts b/test/hapAppDcameraSample/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b365cacd0191d3b1178eb6b9807b1ae0add6271 --- /dev/null +++ b/test/hapAppDcameraSample/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/test/hapAppDcameraSample/oh-package-lock.json5 b/test/hapAppDcameraSample/oh-package-lock.json5 new file mode 100644 index 0000000000000000000000000000000000000000..a39bbd10ee88ce3ea78ab8c5f184ec085a6bb0e5 --- /dev/null +++ b/test/hapAppDcameraSample/oh-package-lock.json5 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0", + "@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19" + }, + "packages": { + "@ohos/hamock@1.0.0": { + "name": "@ohos/hamock", + "version": "1.0.0", + "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==", + "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hamock/-/hamock-1.0.0.har", + "registryType": "ohpm" + }, + "@ohos/hypium@1.0.19": { + "name": "@ohos/hypium", + "version": "1.0.19", + "integrity": "sha512-cEjDgLFCm3cWZDeRXk7agBUkPqjWxUo6AQeiu0gEkb3J8ESqlduQLSIXeo3cCsm8U/asL7iKjF85ZyOuufAGSQ==", + "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.19.har", + "registryType": "ohpm" + } + } +} diff --git a/test/hapAppDcameraSample/oh-package.json5 b/test/hapAppDcameraSample/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..9b142d655b140175b33fe2a0c804ca498119f87f --- /dev/null +++ b/test/hapAppDcameraSample/oh-package.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "modelVersion": "5.0.1", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19", + "@ohos/hamock": "1.0.0" + } +}