diff --git a/validator/acts_validator/AppScope/app.json b/validator/acts_validator/AppScope/app.json index aef203c1fc12a0c9e58daae01fd9ecf21c50315c..7a19732b3c78fd933851a1d57ba28d51d1e34e52 100644 --- a/validator/acts_validator/AppScope/app.json +++ b/validator/acts_validator/AppScope/app.json @@ -10,7 +10,7 @@ "keepAlive": true, "singleUser": true, "minAPIVersion": 9, - "targetAPIVersion": 9, + "targetAPIVersion": 10, "car": { "apiCompatibleVersion": 9, "singleUser": false diff --git a/validator/acts_validator/src/main/ets/pages/Audio/AudioInputRoutingTypeC.ets b/validator/acts_validator/src/main/ets/pages/Audio/AudioInputRoutingTypeC.ets new file mode 100644 index 0000000000000000000000000000000000000000..2ec7fc694a99bb5a5b372dd4bc9608bf4bbd2539 --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/Audio/AudioInputRoutingTypeC.ets @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2023 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 {CustomContainer} from '../common/AudioContainer'; +import FirstDialog from '../model/FirstDialog'; +import AudioCapturer from '../model/AudioCapturer' +import Logger from '../model/Logger' +import prompt from '@ohos.prompt'; +import audio from '@ohos.multimedia.audio' +import router from '@ohos.router'; +import mediaPlay from '../model/mediaPlay' +@Entry +@Component +struct audioInputRouting { + @State name: string = 'AudioInputRoutingTest(TypeC)'; + @State StepTips: string = '请参考提示信息依次执行如下操作'; + @State Vue: boolean = false; + private tag: string = 'qlw' + @State deviceChange: audio.DeviceChangeAction = undefined + @State audioRoutingManager: audio.AudioRoutingManager = undefined + @State yesEnable: boolean = false + @State recorderEnable: boolean = false + @State stopEnable: boolean = false + @State playEnable: boolean = false + @State inputDevice: string = '' + async aboutToAppear(){ + await FirstDialog.ChooseDialog(this.StepTips,this.name); + await this.onDeviceChange() + await this.getDevices() + } + onPageHide() { + AudioCapturer.releaseCapturer() + Logger.info(this.tag, `onPageHide releaseCapturer end`) + mediaPlay.release() + Logger.info(this.tag, `onPageHide releaseAVplayer end`) + } + + async onDeviceChange(){ + this.audioRoutingManager = await audio.getAudioManager().getRoutingManager() + this.audioRoutingManager.on('deviceChange', audio.DeviceFlag.ALL_DEVICES_FLAG, async(DeviceChangeAction) => { + Logger.info(this.tag, `deviceChange: ` + JSON.stringify(DeviceChangeAction)) + await this.getDevices() + }) + } + + async getDevices(){ + try{ + Logger.info(this.tag, `getDevices test `) + let deviceDescriptors = await this.audioRoutingManager.getDevices(audio.DeviceFlag.INPUT_DEVICES_FLAG) + Logger.info(this.tag, `getDevices: ` + JSON.stringify(deviceDescriptors)) + switch (deviceDescriptors[0].deviceType) { + case 3: + this.inputDevice = "3.5mm有线耳机" + break + case 8: + this.inputDevice = "蓝牙耳机" + break + case 15: + this.inputDevice = "mic" + break + case 22: + this.inputDevice = "Type C" + break + default: + break + } + Logger.info(this.tag, `InputDeviceList: ${this.inputDevice}`) + }catch(err){ + Logger.info(this.tag, `getDevices err message: ${err.message}, err code: ${err.code} `) + } + } + + build() { + Column() { + Row() { + Button(){ + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({left:'20vp'}) + }.backgroundColor(Color.Black) + .onClick(()=>{ + router.back({ + url:'pages/Audio/Audio_index', + params: {result : 'None',} + }) + }) + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({left:'-20vp'}) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + Column() { + Flex({direction:FlexDirection.Column,alignItems: ItemAlign.Start, justifyContent: FlexAlign.SpaceBetween }) { + Column(){ + Row(){ + Text(`是否设备支持TypeC耳机?`).fontColor(Color.White).fontSize('18fp') + } + Row(){ + Column(){ + Button(`No`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(!this.yesEnable) + .opacity(!this.yesEnable? 1 : 0.4) + .onClick(async () => { + this.Vue = true + }) + } + Column(){ + Button(`Yes`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .onClick(async () => { + this.yesEnable = true + this.recorderEnable = true + }) + } + } + Row(){ + Text('测试目的:\n当设备连接TypeC耳机时,是否音频输入路由正确切换\n测试准备\n断连任何外设,保持设备常亮\n测试步骤:\n1. 验证设备是否支持TypeC耳机\n2. 按下RECORD按钮\n3. 连接TypeC耳机\n4. 对着耳机mic讲话\n5. 按下STOP按钮\n6. 按下PLAY按钮听录制音频正常播放\n测试标准:\n如果设备不支持TypeC耳机输入或者接收到输入路由通知、路由显示为TypeC耳机,通过TypeC可正常录制和播放,则用例pass').fontColor(Color.White).fontSize('18fp') + } + Row(){ + Text(`Audio输入路由:${this.inputDevice}`).fontColor(Color.White).fontSize('18fp') + } + Row(){ + Column(){ + Button(`RECORD`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(this.recorderEnable) + .opacity(this.recorderEnable ? 1 : 0.4) + .onClick(async () => { + this.stopEnable = true + this.recorderEnable = false + await AudioCapturer.createAudioCapturer() + await AudioCapturer.startCapturer() + }) + } + Column(){ + Button(`STOP`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(this.stopEnable) + .opacity(this.stopEnable ? 1 : 0.4) + .onClick(async () => { + this.recorderEnable = true + this.stopEnable = false + this.playEnable = true + await AudioCapturer.stopCapturer() + await AudioCapturer.releaseCapturer() + }) + } + Column(){ + Button(`PLAY`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(this.playEnable) + .opacity(this.playEnable ? 1 : 0.4) + .onClick(async () => { + this.playEnable = false + await mediaPlay.init() + this.Vue = true + }) + } + } + } + + } + }.width('100%').height('80%').backgroundColor(Color.Black) + .justifyContent(FlexAlign.SpaceEvenly) + CustomContainer({ + title: this.name, + Url:'pages/Audio/Audio_index', + StepTips:this.StepTips, + name:$name, + Vue: $Vue, + }).height('10%').width('100%') + }.width('100%').height('100%').backgroundColor(Color.Black) + } +} diff --git a/validator/acts_validator/src/main/ets/pages/Audio/AudioInputRoutingWiredHeadset.ets b/validator/acts_validator/src/main/ets/pages/Audio/AudioInputRoutingWiredHeadset.ets new file mode 100644 index 0000000000000000000000000000000000000000..2dbe3c734aa3d5bdee232b940a120bbb0acbe04a --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/Audio/AudioInputRoutingWiredHeadset.ets @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2023 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 {CustomContainer} from '../common/AudioContainer'; +import FirstDialog from '../model/FirstDialog'; +import AudioCapturer from '../model/AudioCapturer' +import Logger from '../model/Logger' +import prompt from '@ohos.prompt'; +import audio from '@ohos.multimedia.audio' +import router from '@ohos.router'; +import mediaPlay from '../model/mediaPlay' +@Entry +@Component +struct audioInputRouting { + @State name: string = 'AudioInputRoutingTest(WiredHeadset)'; + @State StepTips: string = '请参考提示信息依次执行如下操作'; + @State Vue: boolean = false; + private tag: string = 'qlw' + @State deviceChange: audio.DeviceChangeAction = undefined + @State audioRoutingManager: audio.AudioRoutingManager = undefined + @State yesEnable: boolean = false + @State recorderEnable: boolean = false + @State stopEnable: boolean = false + @State playEnable: boolean = false + @State inputDevice: string = '' + async aboutToAppear(){ + await FirstDialog.ChooseDialog(this.StepTips,this.name); + await this.onDeviceChange() + await this.getDevices() + } + onPageHide() { + AudioCapturer.releaseCapturer() + Logger.info(this.tag, `onPageHide releaseCapturer end`) + mediaPlay.release() + Logger.info(this.tag, `onPageHide releaseAVplayer end`) + } + + async onDeviceChange(){ + this.audioRoutingManager = await audio.getAudioManager().getRoutingManager() + this.audioRoutingManager.on('deviceChange', audio.DeviceFlag.ALL_DEVICES_FLAG, async(DeviceChangeAction) => { + Logger.info(this.tag, `deviceChange: ` + JSON.stringify(DeviceChangeAction)) + await this.getDevices() + }) + } + + async getDevices(){ + try{ + Logger.info(this.tag, `getDevices test `) + let deviceDescriptors = await this.audioRoutingManager.getDevices(audio.DeviceFlag.INPUT_DEVICES_FLAG) + Logger.info(this.tag, `getDevices: ` + JSON.stringify(deviceDescriptors)) + switch (deviceDescriptors[0].deviceType) { + case 3: + this.inputDevice = "3.5mm有线耳机" + break + case 8: + this.inputDevice = "蓝牙耳机" + break + case 15: + this.inputDevice = "mic" + break + case 22: + this.inputDevice = "Type C" + break + default: + break + } + Logger.info(this.tag, `InputDeviceList: ${this.inputDevice}`) + }catch(err){ + Logger.info(this.tag, `getDevices err message: ${err.message}, err code: ${err.code} `) + } + } + + build() { + Column() { + Row() { + Button(){ + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({left:'20vp'}) + }.backgroundColor(Color.Black) + .onClick(()=>{ + router.back({ + url:'pages/Audio/Audio_index', + params: {result : 'None',} + }) + }) + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({left:'-20vp'}) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + Column() { + Flex({direction:FlexDirection.Column,alignItems: ItemAlign.Start, justifyContent: FlexAlign.SpaceBetween }) { + Column(){ + Row(){ + Text(`是否设备支持3.5mm耳机?`).fontColor(Color.White).fontSize('18fp') + } + Row(){ + Column(){ + Button(`No`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(!this.yesEnable) + .opacity(!this.yesEnable? 1 : 0.4) + .onClick(async () => { + this.Vue = true + }) + } + Column(){ + Button(`Yes`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .onClick(async () => { + this.yesEnable = true + this.recorderEnable = true + }) + } + } + Row(){ + Text('测试目的:\n当设备连接3.5mm有线耳机时,是否音频输入路由正确切换\n测试准备\n断连任何外设,保持设备常亮\n测试步骤:\n1. 验证设备是否支持3.5mm有线耳机\n2. 按下RECORD按钮\n3. 连接3.5mm有线耳机\n4. 对着耳机mic讲话\n5. 按下STOP按钮\n6. 按下PLAY按钮听录制音频正常播放\n测试标准:\n如果设备不支持3.5mm有线耳机输入或者接收到路由通知、路由显示为3.5mm耳机,通过3.5mm耳机可正常录制和播放,则用例pass').fontColor(Color.White).fontSize('18fp') + } + Row(){ + Text(`Audio输入路由:${this.inputDevice}`).fontColor(Color.White).fontSize('18fp') + } + Row(){ + Column(){ + Button(`RECORD`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(this.recorderEnable) + .opacity(this.recorderEnable ? 1 : 0.4) + .onClick(async () => { + this.stopEnable = true + this.recorderEnable = false + await AudioCapturer.createAudioCapturer() + await AudioCapturer.startCapturer() + }) + } + Column(){ + Button(`STOP`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(this.stopEnable) + .opacity(this.stopEnable ? 1 : 0.4) + .onClick(async () => { + this.recorderEnable = true + this.stopEnable = false + this.playEnable = true + await AudioCapturer.stopCapturer() + await AudioCapturer.releaseCapturer() + }) + } + Column(){ + Button(`PLAY`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(this.playEnable) + .opacity(this.playEnable ? 1 : 0.4) + .onClick(async () => { + this.playEnable = false + await mediaPlay.init() + this.Vue = true + }) + } + } + } + + } + }.width('100%').height('80%').backgroundColor(Color.Black) + .justifyContent(FlexAlign.SpaceEvenly) + CustomContainer({ + title: this.name, + Url:'pages/Audio/Audio_index', + StepTips:this.StepTips, + name:$name, + Vue: $Vue, + }).height('10%').width('100%') + }.width('100%').height('100%').backgroundColor(Color.Black) + } +} diff --git a/validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingBT.ets b/validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingBT.ets new file mode 100644 index 0000000000000000000000000000000000000000..1a22cd849d24b7767fc5fa8a28b48b428672b066 --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingBT.ets @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2023 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 {CustomContainer} from '../common/AudioContainer'; +import FirstDialog from '../model/FirstDialog'; +import AudioRenderer from '../model/AudioRenderer' +import Logger from '../model/Logger' +import prompt from '@ohos.prompt'; +import audio from '@ohos.multimedia.audio' +import router from '@ohos.router'; +@Entry +@Component +struct audioOutputRouting { + @State name: string = 'AudioOutputRoutingTest(BT)'; + @State StepTips: string = '请参考提示信息依次执行如下操作'; + @State Vue: boolean = false; + private tag: string = 'qlw' + @State audioRoutingManager: audio.AudioRoutingManager = undefined + @State yesEnable: boolean = false + @State playEnable: boolean = false + @State stopEnable: boolean = false + @State outputDevice: string = '' + async aboutToAppear(){ + await FirstDialog.ChooseDialog(this.StepTips,this.name); + await this.onDeviceChange() + await this.getDevices() + } + onPageHide() { + AudioRenderer.releaseRenderer() + Logger.info(this.tag, `onPageHide releaseRenderer end`) + } + + async onDeviceChange(){ + this.audioRoutingManager = await audio.getAudioManager().getRoutingManager() + this.audioRoutingManager.on('deviceChange', audio.DeviceFlag.ALL_DEVICES_FLAG, async(DeviceChangeAction) => { + Logger.info(this.tag, `deviceChange: ` + JSON.stringify(DeviceChangeAction)) + await this.getDevices() + }) + } + + async getDevices(){ + let deviceDescriptors = await this.audioRoutingManager.getDevices(audio.DeviceFlag.OUTPUT_DEVICES_FLAG) + Logger.info(this.tag, `getDevices: ` + JSON.stringify(deviceDescriptors)) + switch (deviceDescriptors[0].deviceType) { + case 2: + this.outputDevice = "Speaker" + break + case 3: + this.outputDevice = "3.5mm有线耳机" + break + case 8: + this.outputDevice = "蓝牙耳机" + break + case 22: + this.outputDevice = "Type C耳机" + break + default: + break + } + Logger.info(this.tag, `OutputDeviceList: ${this.outputDevice}`) + } + + build() { + Column() { + Row() { + Button(){ + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({left:'20vp'}) + }.backgroundColor(Color.Black) + .onClick(()=>{ + router.back({ + url:'pages/Audio/Audio_index', + params: {result : 'None',} + }) + }) + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({left:'-20vp'}) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + Column() { + Flex({direction:FlexDirection.Column,alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) { + Column(){ + Row(){ + Text(`是否设备支持蓝牙耳机?`).fontColor(Color.White).fontSize('18fp') + } + Row(){ + Column(){ + Button(`No`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(!this.yesEnable) + .opacity(!this.yesEnable? 1 : 0.4) + .onClick(async () => { + this.Vue = true + }) + } + Column(){ + Button(`Yes`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .onClick(async () => { + this.yesEnable = true + this.playEnable = true + + }) + } + } + Row(){ + Text('测试目的:\n当设备连接蓝牙耳机时,音频路由是否正确切换\n测试准备:\n断连任何外设,保持设备常亮\n测试步骤:\n1. 验证设备是否支持蓝牙外设\n2. 按下PLAY按钮\n3. 连接蓝牙耳机\n4. 拔出蓝牙耳机\n5. 按下STOP按钮\n测试标准:\n如果设备不支持蓝牙耳机连接或者插拔蓝牙耳机后接收到路由通知、路由显示正确,且连接蓝牙后音频通过蓝牙耳机播放,则用例pass').fontColor(Color.White).fontSize('18fp') + + } + Row(){ + Text(`Audio输出路由:${this.outputDevice}`).fontColor(Color.White).fontSize('18fp') + } + Row(){ + Column(){ + Button(`PLAY`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(this.playEnable) + .opacity(this.playEnable? 1 : 0.4) + .onClick(async () => { + this.Vue = true + this.stopEnable = true + this.playEnable = false + await AudioRenderer.createAudioRenderer() + await AudioRenderer.startRenderer() + + }) + } + Column(){ + Button(`STOP`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(this.stopEnable) + .opacity(this.stopEnable? 1 : 0.4) + .onClick(async () => { + await AudioRenderer.stopRenderer() + await AudioRenderer.releaseRenderer() + this.playEnable = true + this.stopEnable = false + }) + } + } + } + + } + }.width('100%').height('80%').backgroundColor(Color.Black) + .justifyContent(FlexAlign.SpaceEvenly) + CustomContainer({ + title: this.name, + Url:'pages/Audio/Audio_index', + StepTips:this.StepTips, + name:$name, + Vue: $Vue, + }).height('10%').width('100%') + }.width('100%').height('100%').backgroundColor(Color.Black) + } +} diff --git a/validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingTypeC.ets b/validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingTypeC.ets new file mode 100644 index 0000000000000000000000000000000000000000..03e5acd411138d17f52b370eb5cb7dbb63f4a7cd --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingTypeC.ets @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2023 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 {CustomContainer} from '../common/AudioContainer'; +import FirstDialog from '../model/FirstDialog'; +import AudioRenderer from '../model/AudioRenderer' +import Logger from '../model/Logger' +import prompt from '@ohos.prompt'; +import audio from '@ohos.multimedia.audio' +import router from '@ohos.router'; +@Entry +@Component +struct audioOutputRouting { + @State name: string = 'AudioOutputRoutingTest(TypeC)'; + @State StepTips: string = '请参考提示信息依次执行如下操作'; + @State Vue: boolean = false; + private tag: string = 'qlw' + @State audioRoutingManager: audio.AudioRoutingManager = undefined + @State yesEnable: boolean = false + @State playEnable: boolean = false + @State stopEnable: boolean = false + @State outputDevice: string = '' + async aboutToAppear(){ + await FirstDialog.ChooseDialog(this.StepTips,this.name); + await this.onDeviceChange() + await this.getDevices() + } + onPageHide() { + AudioRenderer.releaseRenderer() + Logger.info(this.tag, `onPageHide releaseRenderer end`) + } + + async onDeviceChange(){ + this.audioRoutingManager = await audio.getAudioManager().getRoutingManager() + this.audioRoutingManager.on('deviceChange', audio.DeviceFlag.OUTPUT_DEVICES_FLAG, async(DeviceChangeAction) => { + Logger.info(this.tag, `deviceChange: ` + JSON.stringify(DeviceChangeAction)) + await this.getDevices() + }) + } + + async getDevices(){ + let deviceDescriptors = await this.audioRoutingManager.getDevices(audio.DeviceFlag.OUTPUT_DEVICES_FLAG) + Logger.info(this.tag, `getDevices: ` + JSON.stringify(deviceDescriptors)) + switch (deviceDescriptors[0].deviceType) { + case 2: + this.outputDevice = "Speaker" + break + case 3: + this.outputDevice = "3.5mm有线耳机" + break + case 8: + this.outputDevice = "蓝牙耳机" + break + case 22: + this.outputDevice = "Type C耳机" + break + default: + break + } + Logger.info(this.tag, `OutputDeviceList: ${this.outputDevice}`) + } + + build() { + Column() { + Row() { + Button(){ + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({left:'20vp'}) + }.backgroundColor(Color.Black) + .onClick(()=>{ + router.back({ + url:'pages/Audio/Audio_index', + params: {result : 'None',} + }) + }) + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({left:'-20vp'}) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + Column() { + Flex({direction:FlexDirection.Column,alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) { + Column(){ + Row(){ + Text(`是否设备支持TypeC耳机?`).fontColor(Color.White).fontSize('18fp') + } + Row(){ + Column(){ + Button(`No`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(!this.yesEnable) + .opacity(!this.yesEnable? 1 : 0.4) + .onClick(async () => { + this.Vue = true + }) + } + Column(){ + Button(`Yes`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .onClick(async () => { + this.yesEnable = true + this.playEnable = true + + }) + } + } + Row(){ + Text('测试目的:\n当设备连接TypeC耳机时,音频路由是否正确切换\n测试准备:\n断连任何外设,保持设备常亮\n测试步骤:\n1. 验证设备是否支持TypeC外设\n2. 按下PLAY按钮\n3. 连接TypeC耳机\n4. 拔出TypeC耳机\n5. 按下STOP按钮\n测试标准:\n如果设备不支持TypeC耳机连接或者插拔TypeC耳机后接收到路由通知、路由显示正确,且连接TypeC后音频通过TypeC耳机播放,则用例pass').fontColor(Color.White).fontSize('18fp') + + } + Row(){ + Text(`Audio输出路由:${this.outputDevice}`).fontColor(Color.White).fontSize('18fp') + } + Row(){ + Column(){ + Button(`PLAY`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(this.playEnable) + .opacity(this.playEnable? 1 : 0.4) + .onClick(async () => { + this.Vue = true + this.stopEnable = true + this.playEnable = false + await AudioRenderer.createAudioRenderer() + await AudioRenderer.startRenderer() + + }) + } + Column(){ + Button(`STOP`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(this.stopEnable) + .opacity(this.stopEnable? 1 : 0.4) + .onClick(async () => { + await AudioRenderer.stopRenderer() + await AudioRenderer.releaseRenderer() + this.playEnable = true + this.stopEnable = false + }) + } + } + } + + } + }.width('100%').height('80%').backgroundColor(Color.Black) + .justifyContent(FlexAlign.SpaceEvenly) + CustomContainer({ + title: this.name, + Url:'pages/Audio/Audio_index', + StepTips:this.StepTips, + name:$name, + Vue: $Vue, + }).height('10%').width('100%') + }.width('100%').height('100%').backgroundColor(Color.Black) + } +} diff --git a/validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingWiredHeadset.ets b/validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingWiredHeadset.ets new file mode 100644 index 0000000000000000000000000000000000000000..6a2d1e0888c6b21d292e1a6bf33916780c920c20 --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingWiredHeadset.ets @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2023 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 {CustomContainer} from '../common/AudioContainer'; +import FirstDialog from '../model/FirstDialog'; +import AudioRenderer from '../model/AudioRenderer' +import Logger from '../model/Logger' +import prompt from '@ohos.prompt'; +import audio from '@ohos.multimedia.audio' +import router from '@ohos.router'; +@Entry +@Component +struct audioOutputRouting { + @State name: string = 'AudioOutputRoutingTest(WiredHeadset)'; + @State StepTips: string = '请参考提示信息依次执行如下操作'; + @State Vue: boolean = false; + private tag: string = 'qlw' + @State audioRoutingManager: audio.AudioRoutingManager = undefined + @State yesEnable: boolean = false + @State playEnable: boolean = false + @State stopEnable: boolean = false + @State outputDevice: string = '' + async aboutToAppear(){ + await FirstDialog.ChooseDialog(this.StepTips,this.name); + await this.onDeviceChange() + await this.getDevices() + } + onPageHide() { + AudioRenderer.releaseRenderer() + Logger.info(this.tag, `onPageHide releaseRenderer end`) + } + + async onDeviceChange(){ + this.audioRoutingManager = await audio.getAudioManager().getRoutingManager() + this.audioRoutingManager.on('deviceChange', audio.DeviceFlag.INPUT_DEVICES_FLAG, async(DeviceChangeAction) => { + Logger.info(this.tag, `deviceChange: ` + JSON.stringify(DeviceChangeAction)) + await this.getDevices() + }) + } + + async getDevices(){ + let deviceDescriptors = await this.audioRoutingManager.getDevices(audio.DeviceFlag.OUTPUT_DEVICES_FLAG) + Logger.info(this.tag, `getDevices: ` + JSON.stringify(deviceDescriptors)) + switch (deviceDescriptors[0].deviceType) { + case 2: + this.outputDevice = "Speaker" + break + case 3: + this.outputDevice = "3.5mm有线耳机" + break + case 8: + this.outputDevice = "蓝牙耳机" + break + case 22: + this.outputDevice = "Type C耳机" + break + default: + break + } + Logger.info(this.tag, `OutputDeviceList: ${this.outputDevice}`) + } + + build() { + Column() { + Row() { + Button(){ + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({left:'20vp'}) + }.backgroundColor(Color.Black) + .onClick(()=>{ + router.back({ + url:'pages/Audio/Audio_index', + params: {result : 'None',} + }) + }) + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({left:'-20vp'}) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + Column() { + Flex({direction:FlexDirection.Column,alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) { + Column(){ + Row(){ + Text(`是否设备支持3.5mm有线耳机?`).fontColor(Color.White).fontSize('18fp') + } + Row(){ + Column(){ + Button(`No`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(!this.yesEnable) + .opacity(!this.yesEnable? 1 : 0.4) + .onClick(async () => { + this.Vue = true + }) + } + Column(){ + Button(`Yes`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .onClick(async () => { + this.yesEnable = true + this.playEnable = true + + }) + } + } + Row(){ + Text('测试目的:\n当设备连接3.5mm有线耳机时,音频路由是否正确切换\n测试准备:\n断连任何外设,保持设备常亮\n测试步骤:\n1. 验证设备是否支持外设\n2. 按下PLAY按钮\n3. 连接3.5mm有线耳机\n4. 拔出3.5mm有线耳机\n5. 按下STOP按钮\n测试标准:\n如果设备不支持有线耳机输入或者插入和拔出有线耳机后接收到路由通知,路由显示正确,且连接外设后音频通过外设播放,则用例pass').fontColor(Color.White).fontSize('18fp') + + } + Row(){ + Text(`Audio输出路由:${this.outputDevice}`).fontColor(Color.White).fontSize('18fp') + } + Row(){ + Column(){ + Button(`PLAY`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(this.playEnable) + .opacity(this.playEnable? 1 : 0.4) + .onClick(async () => { + this.Vue = true + this.stopEnable = true + this.playEnable = false + await AudioRenderer.createAudioRenderer() + await AudioRenderer.startRenderer() + + }) + } + Column(){ + Button(`STOP`) + .borderRadius(8) + .backgroundColor(0x317aff) + .width('30%') + .enabled(this.stopEnable) + .opacity(this.stopEnable? 1 : 0.4) + .onClick(async () => { + await AudioRenderer.stopRenderer() + await AudioRenderer.releaseRenderer() + this.playEnable = true + this.stopEnable = false + }) + } + } + } + } + }.width('100%').height('80%').backgroundColor(Color.Black) + .justifyContent(FlexAlign.SpaceEvenly) + CustomContainer({ + title: this.name, + Url:'pages/Audio/Audio_index', + StepTips:this.StepTips, + name:$name, + Vue: $Vue, + }).height('10%').width('100%') + }.width('100%').height('100%').backgroundColor(Color.Black) + } +} diff --git a/validator/acts_validator/src/main/ets/pages/Audio/Audio_index.ets b/validator/acts_validator/src/main/ets/pages/Audio/Audio_index.ets index 51bb57324f531a401b8a5600368ea81f2717b799..05afa24724568084d19ed41f52030083350006c4 100644 --- a/validator/acts_validator/src/main/ets/pages/Audio/Audio_index.ets +++ b/validator/acts_validator/src/main/ets/pages/Audio/Audio_index.ets @@ -39,7 +39,11 @@ struct IndexPage { @State result : string = ''; @State TEST : number = 0; private TestCaseList = [ - {title:'ScrollingList',uri:'pages/Audio/ScrollListTest'}, + {title:'AudioInputRoutingTest(WiredHeadset)',uri:'pages/Audio/AudioInputRoutingWiredHeadset'}, + {title:'AudioInputRoutingTest(TypeC)',uri:'pages/Audio/AudioInputRoutingTypeC'}, + {title:'AudioOutputRoutingTest(WiredHeadset)',uri:'pages/Audio/AudioOutputRoutingWiredHeadset'}, + {title:'AudioOutputRoutingTest(TypeC)',uri:'pages/Audio/AudioOutputRoutingTypeC'}, + {title:'AudioOutputRoutingTest(BT)',uri:'pages/Audio/AudioOutputRoutingBT'}, ] @State ColorObject : string[] = VarColor; async onPageShow(){ diff --git a/validator/acts_validator/src/main/ets/pages/Audio/ScrollListTest.ets b/validator/acts_validator/src/main/ets/pages/Audio/ScrollListTest.ets deleted file mode 100644 index c7ac4c6f146811dc5eae2f01b915a88c22596662..0000000000000000000000000000000000000000 --- a/validator/acts_validator/src/main/ets/pages/Audio/ScrollListTest.ets +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 {CustomContainer} from '../common/CustomContainer'; -import FirstDialog from '../model/FirstDialog'; -@Entry -@Component -struct CustomContainerUser { - private listArr: number[] = Array.from(new Array(50).keys()); - @State name: string = 'ScrollingList'; - @State StepTips: string = '操作步骤:滑动列表观察是否能正常滑动'+'\n'+'预期结果:列表滑动正常'; - @State Vue: boolean = false; - async aboutToAppear(){ - await FirstDialog.ChooseDialog(this.StepTips,this.name); - this.Vue = true; - } - @Builder specificNoParam() { - Column() { - List() { - ForEach(this.listArr,(item:any,index:number) => { - ListItem() { - Text('Item #' + (index + 1)).width('100%').height(50).fontSize(16).fontColor(Color.White).margin({left:'10vp'}) - } - },index => index) - }.height('100%').width('100%').divider({strokeWidth:1,color:Color.Grey}) - }.height('83%').width('100%') - } - build() { - Column() { - CustomContainer({ - title: this.name, - Url: 'pages/Audio/Audio_index', - StepTips: this.StepTips, - content: this.specificNoParam.bind(this), - name: $name, - Vue: $Vue, - }) - }.width('100%').height('100%').backgroundColor(Color.Black) - } -} diff --git a/validator/acts_validator/src/main/ets/pages/Camera/CameraFlash.ets b/validator/acts_validator/src/main/ets/pages/Camera/CameraFlash.ets new file mode 100644 index 0000000000000000000000000000000000000000..1fe7c4423cc298e0be4a42b1acc9b6e3e5b99222 --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/Camera/CameraFlash.ets @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2023 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. + */ +// @ts-nocheck +// @ts-ignore +import camera from '@ohos.multimedia.camera' +import Logger from '../model/Logger' +import CameraService from '../model/CameraService' +import { CustomContainer } from '../common/CameraFlashContainer'; +import FirstDialog from '../model/FirstDialog'; +import router from '@ohos.router'; + +@Entry +@Component +struct cameraOrientation { + @State FillColor: string = '#FF000000'; + @State name: string = 'CameraFlash'; + @State StepTips: string = '测试目的:用于测试相机闪光灯能力\n-确定是否有闪光灯\n-根据设备选择选项\n-点击开启关闭对闪光灯进行操作' + '\n' + '预期结果:操作后闪关灯表现一致'; + private tag: string = 'qlw CameraFlash' + @State Vue: boolean = false + @State isFlash: boolean = undefined + private mXComponentController: XComponentController = new XComponentController() + @State captureSession: camera.CaptureSession = undefined + @State flashChange: boolean = false + + async aboutToAppear() { + await FirstDialog.ChooseDialog(this.StepTips, this.name) + this.cameraIsFlash() + } + + cameraInit() { + // @ts-ignore + this.surfaceId = this.mXComponentController.getXComponentSurfaceId() + CameraService.initCamera(this.surfaceId, 0).then(() => { + this.captureSession = CameraService.captureSession + this.isFlash = this.captureSession.hasFlash() + Logger.info(this.tag, `onLoad isFlash: ${this.isFlash}`) + }) + } + + openFlash() { + this.flashChange = !this.flashChange + if (this.isFlash) { + // 设置当前设备的闪光灯模式 + this.captureSession.setFlashMode(this.flashChange ? camera.FlashMode.FLASH_MODE_ALWAYS_OPEN : camera.FlashMode.FLASH_MODE_CLOSE) + if (!this.flashChange){ + this.Vue = true + } + Logger.info(this.tag, `setFlashMode success`) + // 获取当前设备的闪光灯模式 + let flashMode = this.captureSession.getFlashMode() + Logger.info(this.tag, `getFlashMode success: ${flashMode}`) + } + } + + onPageShow() { + this.cameraInit() + } + + onPageHide() { + CameraService.releaseCamera() + Logger.info(this.tag, `onPageHide releaseCamera end`) + } + + build() { + Column() { + Row() { + Button() { + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({ left: '20vp' }) + }.backgroundColor(Color.Black) + .onClick(() => { + router.back({ + url: 'pages/Camera/Camera_index', + params: { result: 'None', } + }) + }) + + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({ left: '-20vp' }) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + + Stack() { + XComponent({ + id: 'componentId', + type: 'surface', + controller: this.mXComponentController + }) + .onLoad(async () => { + Logger.info(this.tag, 'onLoad is called') + this.cameraInit() + }) + Row().backgroundColor(Color.Black).size({ width: '100%', height: '100%' }) + }.size({ width: '10%', height: '30%' }) + + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start, direction: FlexDirection.Column }) { + // Text(`提示:` + this.isFlash).fontSize('16fp').fontColor(Color.White) + Text(`提示:如果设备存在闪光灯,选择开启,否则选择无闪光灯`) + .fontSize('16fp').fontColor(Color.White).margin('20fp') + Row() { + Button(this.flashChange ? '关闭' : '开启').onClick(() => { + this.openFlash() + }) + Button('无闪光灯').onClick(() => { + this.Vue = true + }) + }.justifyContent(FlexAlign.SpaceEvenly).width('100%').margin('20fp') + }.width('80%').height('50%') + + + CustomContainer({ + title: this.name, + Url: 'pages/Camera/Camera_index', + StepTips: this.StepTips, + FillColor: $FillColor, + name: $name, + Vue: $Vue, + isFlash:$isFlash + }).height('10%').width('100%') + }.width('100%').height('100%').backgroundColor(Color.Black) + } +} \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/Camera/CameraFormat.ets b/validator/acts_validator/src/main/ets/pages/Camera/CameraFormat.ets deleted file mode 100644 index b19ef842afbf7a80b56ef32263d31b41477c2466..0000000000000000000000000000000000000000 --- a/validator/acts_validator/src/main/ets/pages/Camera/CameraFormat.ets +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2022-2023 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 '@ohos.multimedia.camera' -import Logger from '../model/Logger' -import CameraService from '../model/CameraService' -import {CustomContainer} from '../common/CameraOrientation'; -import FirstDialog from '../model/FirstDialog'; -const CameraMode = { - MODE_PHOTO: 0, // 拍照模式 - MODE_VIDEO: 1 // 录像模式 -} - -@Entry -@Component -struct SetCircle { - @State FillColor: string = '#FF000000'; - @State name: string = 'CameraFormat'; - @State StepTips: string = '测试目的:用于测试相机预览和拍照旋转能力\n-左侧显示给定旋转角度后的预览窗口\n-右侧显示拍照后的图片\n-对于前置摄像头会有镜像效果'+'\n'+'预期结果:拍照图片与预览窗口的画面一致'; - private tag: string = 'qlw' - private mXComponentController: XComponentController = new XComponentController() - @State surfaceId: number = 0; - private x: number = 0; - @State curModel: number = CameraMode.MODE_PHOTO - @State cameraDeviceIndex: number = 0 - @State imageRotationValue: number = camera.ImageRotation.ROTATION_90 - @State qualityLevelValue: number = camera.QualityLevel.QUALITY_LEVEL_LOW - @State photoUri: string = undefined - @State Vue: boolean = false - async aboutToAppear(){ - await FirstDialog.ChooseDialog(this.StepTips,this.name); - } - handleTakePicture = (photoUri: string) => { - this.photoUri = photoUri - Logger.info(this.tag, `takePicture end, photoUri: ${this.photoUri}`) - } - - @Builder specificNoParam() { - Column() { - } - } - build() { - Column() { - CustomContainer({ - title: this.name, - Url:'pages/Camera/Camera_index', - StepTips:this.StepTips, - content: this.specificNoParam, - FillColor:$FillColor, - name: $name, - Vue: $Vue - }).height('30%').width('100%') - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) { - XComponent({ - id: 'componentId', - type: 'surface', - controller: this.mXComponentController - }) - .onLoad(async () => { - Logger.info(this.tag, 'onLoad is called') - // @ts-ignore - this.mXComponentController.setXComponentSurfaceSize({ surfaceWidth: 10, surfaceHeight: 10 }) - // @ts-ignore - this.surfaceId = this.mXComponentController.getXComponentSurfaceId() - Logger.info(this.tag, `onLoad surfaceId: ${this.surfaceId}`) - this.curModel = CameraMode.MODE_PHOTO - CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex) - }) - .height('40%') - .width('40%') - Text('Camera Preview').fontSize('20fp') - Text('Camera').fontSize(20) -// Select(qualityLevel) -// .selected(2) -// .value('请选择') -// .font({ size: 20, weight: 20, family: 'serif', style: FontStyle.Normal }) -// .selectedOptionFont({ size: 20, weight: 20, family: 'serif', style: FontStyle.Normal }) -// .optionFont({ size: 20, weight: 40, family: 'serif', style: FontStyle.Normal }) -// .onSelect((index: number, value: string) => { -// console.info("Select:" + index) -// console.info("Select qualityLevelValue:" + value) -// this.qualityLevelValue = Number(value) -// }) - Button('NEXT', { - type: ButtonType.Normal, - stateEffect: true - }).borderRadius(8).backgroundColor(0x317aff).width('20%').onClick(() => { - CameraService.takePicture(this.imageRotationValue, this.qualityLevelValue) - CameraService.setTakePictureCallback(this.handleTakePicture.bind(this)) - this.Vue = true - }) - }.width('100%').height('70%').backgroundColor(Color.White) - }.width('100%').height('100%').backgroundColor(Color.Black) - } -} -//@CustomDialog -//struct CustomDialogExample { -// @Link textValue: string -// @Link inputValue: string -// @Link qualityLevelValue: number -// @Link imageRotationValue: number -// @Link imageResolutionValue: string -// controller: CustomDialogController -// cancel: () => void -// confirm: () => void -//} \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/Camera/CameraOrientation.ets b/validator/acts_validator/src/main/ets/pages/Camera/CameraOrientation.ets new file mode 100644 index 0000000000000000000000000000000000000000..8862d61cdeb1044518de82bb4ce3c3f45bb89990 --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/Camera/CameraOrientation.ets @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2023 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. + */ + +// @ts-ignore +import camera from '@ohos.multimedia.camera' +import Logger from '../model/Logger' +import CameraService from '../model/CameraService' +import { CustomContainer } from '../common/CameraOrientationContainer'; +import FirstDialog from '../model/FirstDialog'; +import router from '@ohos.router'; + +@Entry +@Component +struct cameraOrientation { + @State FillColor: string = '#FF000000'; + @State name: string = 'CameraOrientation'; + @State StepTips: string = '测试目的:用于测试相机预览和拍照旋转能力\n-左侧显示给定旋转角度后的预览窗口\n-右侧显示拍照后的图片\n-对于前置摄像头会有镜像效果' + '\n' + '预期结果:拍照图片与预览窗口的画面一致'; + private tag: string = 'qlw CameraOrientation' + private mXComponentController: XComponentController = new XComponentController() + @State surfaceId: number = 0; + @State cameraDeviceIndex: number = 0 + @State assetUri: string = undefined + @State Vue: boolean = false + @State imageRotation: number = 0 + @State cameraListLength: number = undefined + @State cameraList: SelectOption[] = [] + @State takeFlag: boolean = true + @State testingFrequency: number = undefined + @State isEnabled: boolean = true + @State takeSelect: number = 0 + @State clickFrequency: number = 0 + + async aboutToAppear() { + await FirstDialog.ChooseDialog(this.StepTips, this.name); + CameraService.setTakePictureCallback(this.handleTakePicture.bind(this)) + } + + onChangeTake() { + if (this.takeFlag) { + CameraService.takePicture(this.imageRotation) + this.Vue = true + this.takeFlag = false + this.isEnabled = false + } else { + this.takeFlag = true + // next 刷新数据 + // 图像置为黑色 + this.assetUri = '' + this.imageRotation = this.imageRotation + 90 + if (this.imageRotation > 270 && this.clickFrequency > 3) { + this.imageRotation = 0 + this.cameraDeviceIndex = 1 + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex) + } + } + } + + cameraListFn() { + this.cameraListLength = CameraService.cameras.length + for (let index = 0; index < this.cameraListLength; index++) { + this.cameraList.push({ + value: `Camera ${index}` + }) + } + this.testingFrequency = this.cameraListLength * 4 + } + + handleTakePicture = (assetUri: string) => { + this.assetUri = assetUri + Logger.info(this.tag, `takePicture end, assetUri: ${this.assetUri}`) + } + + onPageShow() { + Logger.info(this.tag, `takePicture end, assetUri`) + // @ts-ignore + this.surfaceId = this.mXComponentController.getXComponentSurfaceId() + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex).then(() => { + this.cameraListFn() + }) + } + + onPageHide() { + CameraService.releaseCamera() + Logger.info(this.tag, `onPageHide releaseCamera end`) + } + + build() { + Column() { + Row() { + Button() { + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({ left: '20vp' }) + }.backgroundColor(Color.Black) + .onClick(() => { + router.back({ + url: 'pages/Camera/Camera_index', + params: { result: 'None', } + }) + }) + + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({ left: '-20vp' }) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceAround }) { + Column() { + XComponent({ + id: 'componentId', + type: 'surface', + controller: this.mXComponentController + }) + .onLoad(async () => { + Logger.info(this.tag, 'onLoad is called') + // @ts-ignore + this.surfaceId = this.mXComponentController.getXComponentSurfaceId() + Logger.info(this.tag, `onLoad surfaceId: ${this.surfaceId}`) + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex).then(() => { + this.cameraListFn() + }) + }) + .size({ width: '100%', height: '100%' }) + Text('Camera Preview').fontSize('20fp').fontColor(Color.White) + }.size({ width: '40%', height: '60%' }) + + Column() { + Image(this.assetUri || '').size({ width: '100%', height: '100%' }).border({ width: 1 }) + Text('Oriented Photo').fontSize('20fp').fontColor(Color.White) + }.size({ width: '40%', height: '60%' }) + }.width('100%').height('50%') + + Flex({ direction: FlexDirection.Column }) { + Text(`Camera: ${this.cameraDeviceIndex}`).fontSize('16fp').fontColor(Color.White) + Text(`Orientation: ${this.imageRotation}°`).fontSize('16fp').fontColor(Color.White) + Text(`逆时针`).fontSize('16fp').fontColor(Color.White) + Text(`提示:`).fontSize('16fp').fontColor(Color.White) + Text(`如果左边窗口旋转后与右边窗口相同,选择pass,否则选择fail`) + .fontSize('16fp').fontColor(Color.White) + }.size({ width: '80%', height: '25%' }) + + Button(this.takeFlag ? '拍照' : '下一个') + .enabled(this.isEnabled) + .opacity(this.isEnabled ? 1 : 0.4) + .width('50%') + .height('5%') + .backgroundColor(0x317aff) + .onClick(async () => { + this.onChangeTake() + }) + + CustomContainer({ + title: this.name, + Url: 'pages/Camera/Camera_index', + StepTips: this.StepTips, + FillColor: $FillColor, + name: $name, + Vue: $Vue, + testingFrequency: this.testingFrequency, + isEnabled: $isEnabled, + clickFrequency: $clickFrequency + }).height('10%').width('100%') + }.width('100%').height('100%').backgroundColor(Color.Black) + } +} \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/Camera/CameraPhotoFormat.ets b/validator/acts_validator/src/main/ets/pages/Camera/CameraPhotoFormat.ets new file mode 100644 index 0000000000000000000000000000000000000000..8b07f5a2b689510cfe4eb8e2c1d05f4ecfc5872c --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/Camera/CameraPhotoFormat.ets @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2023 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. + */ + +// @ts-ignore +import camera from '@ohos.multimedia.camera' +import Logger from '../model/Logger' +import CameraService from '../model/CameraService' +import { CustomContainer } from '../common/CameraPhotoContainer'; +import FirstDialog from '../model/FirstDialog'; +import router from '@ohos.router'; + +@Entry +@Component +struct cameraOrientation { + @State FillColor: string = '#FF000000'; + @State name: string = 'CameraPhotoFormat'; + @State StepTips: string = '测试目的:用于测试相机拍照分辨率能力\n预期结果:所有分辨率均可以拍照,图片与预览一致'; + private tag: string = 'qlw' + private mXComponentController: XComponentController = new XComponentController() + @State surfaceId: number = 0; + @State cameraDeviceIndex: number = 0 + @State assetUri: string = undefined + @State Vue: boolean = false + @State imageRotation: number = 0 + @State cameraListLength: number = undefined + @State cameraList: SelectOption[] = [] + @State isEnabled: boolean = true + @State isNextEnabled: boolean = true + @State takeSelect: number = 0 + @State clickFrequency: number = 0 + @State resolutionSelectVal: string = '' // 下拉框默认value + @State clickSerialPhotoVal: number = 0 + @State timer: number = -1 + @State resolution: SelectOption[] = [] // 分辨率 + @State testingFrequency: number = undefined // 测试总数 + @State isCameraChange: boolean = false + + async aboutToAppear() { + await FirstDialog.ChooseDialog(this.StepTips, this.name); + CameraService.setTakePictureCallback(this.handleTakePicture.bind(this)) + } + + cameraListFn() { + this.cameraList = [] + this.cameraListLength = CameraService.cameras.length + for (let index = 0; index < this.cameraListLength; index++) { + this.cameraList.push({ value: `Camera ${index}` }) + } + // 测试总次数 = 摄像头0的分辨率 + 摄像头1的分辨率 优先以RK为主 + this.testingFrequency = this.resolution.length + Logger.info(this.tag, `testingFrequency ${this.testingFrequency}`) + } + + handleTakePicture = (assetUri: string) => { + this.assetUri = assetUri + Logger.info(this.tag, `takePicture end, assetUri: ${this.assetUri}`) + } + + onPageShow() { + Logger.info(this.tag, `takePicture end, assetUri`) + // @ts-ignore + this.surfaceId = this.mXComponentController.getXComponentSurfaceId() + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex).then(() => { + this.cameraListFn() + }) + } + + async cameraInit(obj?) { + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex, obj, this.clickFrequency).then(() => { + this.resolution = CameraService.previewSizeResolution + this.resolutionSelectVal = String(this.resolution[this.clickFrequency].value) + this.cameraListFn() + }) + } + + onPageHide() { + CameraService.releaseCamera() + Logger.info(this.tag, `onPageHide releaseCamera end`) + } + // 对分辨率数据处理 获取到需要的格式 + dealWithResolutionFn(arr) { + let newResolution = [] + arr.forEach((item) => { + let indexOf = item.value.indexOf("x") + let objW = Number(item.value.slice(0, indexOf)) + let objH = Number(item.value.slice(indexOf + 1)) + let obj = { + format: 2000, + size: { + "width": objW, + "height": objH + } + } + newResolution.push(obj) + }) + return newResolution + } + + build() { + Column() { + Row() { + Button() { + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({ left: '20vp' }) + }.backgroundColor(Color.Black) + .onClick(() => { + router.back({ + url: 'pages/Camera/Camera_index', + params: { result: 'None', } + }) + }) + + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({ left: '-20vp' }) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceAround }) { + Column() { + XComponent({ + id: 'componentId', + type: 'surface', + controller: this.mXComponentController + }) + .onLoad(async () => { + Logger.info(this.tag, 'onLoad is called') + // @ts-ignore + this.surfaceId = this.mXComponentController.getXComponentSurfaceId() + Logger.info(this.tag, `onLoad surfaceId: ${this.surfaceId}`) + this.cameraInit() + }) + .size({ width: '100%', height: '100%' }) + Text('Camera Preview').fontSize('20fp').fontColor(Color.White) + }.size({ width: '40%', height: '60%' }) + + Column() { + Image(this.assetUri || '').size({ width: '100%', height: '100%' }).border({ width: 1 }) + Text('Oriented Photo').fontSize('20fp').fontColor(Color.White) + }.size({ width: '40%', height: '60%' }) + }.width('100%').height('50%') + + Flex({ direction: FlexDirection.Column }) { + Row() { + Select(this.resolution) + .selected(this.clickFrequency) + .value(this.resolutionSelectVal) + .font({ size: 16, weight: 500 }) + .fontColor(Color.White) + .selectedOptionBgColor(Color.Black) + .optionBgColor(Color.Black) + .selectedOptionFont({ size: 16, weight: 400 }) + .optionFont({ size: 16, weight: 400 }) + .onSelect((index: number, value) => { + let indexOf = value.indexOf('x') + let objW = Number(value.slice(0, indexOf)) + let objH = Number(value.slice(indexOf + 1)) + let obj = { + format: 2000, + size: { + "width": objW, + "height": objH + } + } + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex, obj) + Logger.info(this.tag, `onSelect Rotation index: ${index}, value: ${value}, obj: ${obj}`) + }) + Select(this.cameraList) + .selected(this.cameraDeviceIndex) + .value(this.cameraDeviceIndex ? 'Camera 1' : 'Camera 0') + .font({ size: 16, weight: 500 }) + .fontColor(Color.White) + .selectedOptionBgColor(Color.Black) + .optionBgColor(Color.Black) + .selectedOptionFont({ size: 16, weight: 400 }) + .optionFont({ size: 16, weight: 400 }) + .onSelect((index: number) => { + this.cameraDeviceIndex = index + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex).then(() => { + this.cameraListFn() + }) + }) + }.justifyContent(FlexAlign.SpaceEvenly) + + Text(`提示:对不同分辨率的图片进行拍摄,根据拍摄结果选择pass或选择fail`) + .fontSize('16fp').fontColor(Color.White).margin({ top: 20 }) + }.size({ width: '80%', height: '20%' }) + + Row() { + Button('拍照') + .enabled(this.isEnabled) + .opacity(this.isEnabled ? 1 : 0.4) + .width('40%') + .backgroundColor(0x317aff) + .onClick(async () => { + this.isEnabled = false + this.isNextEnabled = false + CameraService.takePicture() + }) + Button('NEXT') + .enabled(!this.isNextEnabled) + .opacity(!this.isNextEnabled ? 1 : 0.4) + .width('40%') + .backgroundColor(0x317aff) + .onClick(async () => { + this.clickFrequency++ + Logger.info(this.tag, `nextClickFn new clickFrequency: ${this.clickFrequency}`) + + if (this.resolution.length == this.clickFrequency || this.resolution.length < this.clickFrequency){ + if (this.isCameraChange){ + this.Vue = true + this.isEnabled = false + this.isNextEnabled = true + return + } + this.cameraDeviceIndex = Number(!this.cameraDeviceIndex) + this.clickFrequency = 0 + await this.cameraInit().then(() => { + this.isCameraChange = true + }) + } + this.isEnabled = true + this.isNextEnabled = true + if (this.clickFrequency){ + let newResolution = this.dealWithResolutionFn(this.resolution) + Logger.info(this.tag, `nextClickFn new Resolution: ${newResolution}`) + this.cameraInit(newResolution[this.clickFrequency]) + this.resolutionSelectVal = String(this.resolution[this.clickFrequency].value) + } + + }) + }.width('100%').justifyContent(FlexAlign.SpaceEvenly) + .height('10%') + + CustomContainer({ + title: this.name, + Url: 'pages/Camera/Camera_index', + StepTips: this.StepTips, + FillColor: $FillColor, + name: $name, + Vue: $Vue + }).height('10%').width('100%') + }.width('100%').height('100%').backgroundColor(Color.Black) + } +} \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/Camera/CameraPreviewFormat.ets b/validator/acts_validator/src/main/ets/pages/Camera/CameraPreviewFormat.ets new file mode 100644 index 0000000000000000000000000000000000000000..8d26e4791fb819700612c76fd10eac1e29eba8af --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/Camera/CameraPreviewFormat.ets @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2023 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. + */ + +// @ts-ignore +import camera from '@ohos.multimedia.camera' +import Logger from '../model/Logger' +import CameraService from '../model/CameraService' +import { CustomContainer } from '../common/CameraPreviewFormatContainer'; +import FirstDialog from '../model/FirstDialog'; +import router from '@ohos.router'; + +@Entry +@Component +struct cameraFormat { + @State FillColor: string = '#FF000000'; + @State name: string = 'CameraPreviewFormat'; + @State StepTips: string = '测试目的:用于测试相机预览分辨率能力\n预期结果:所有分辨率均可以预览成功,预览画面正常'; + private tag: string = 'qlw CameraFormat' + private mXComponentController: XComponentController = new XComponentController() + @State surfaceId: number = 0; + @State cameraDeviceIndex: number = 0 + @State Vue: boolean = false + @State resolution: SelectOption[] = [] + @State testingFrequency: number = undefined + @State clickFrequency: number = 0 + @State cameraListLength: number = undefined + @State cameraList: SelectOption[] = [] + @State resolutionSelectVal: string = '' + @State nextEnabled: boolean = true + @State formatVal: SelectOption[] = [] + + async aboutToAppear() { + await FirstDialog.ChooseDialog(this.StepTips, this.name); + Logger.info(this.tag, `the resolution: ${this.resolution}`) + } + + onPageHide() { + CameraService.releaseCamera() + Logger.info(this.tag, `onPageHide releaseCamera end`) + } + + cameraListFn() { + this.cameraList = [] + this.cameraListLength = CameraService.cameras.length + for (let index = 0; index < this.cameraListLength; index++) { + this.cameraList.push({ value: `Camera ${index}` }) + } + // 测试总次数 = 摄像头0的分辨率 + 摄像头1的分辨率 优先以RK为主 + this.testingFrequency = this.resolution.length + Logger.info(this.tag, `testingFrequency ${this.testingFrequency}`) + } + + async cameraInit(obj?) { + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex, obj).then(() => { + this.resolution = CameraService.resolution + this.resolutionSelectVal = String(this.resolution[this.clickFrequency].value) + this.cameraListFn() + }) + } + + onPageShow() { + Logger.info(this.tag, `takePicture end, assetUri`) + // @ts-ignore + this.surfaceId = this.mXComponentController.getXComponentSurfaceId() + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex).then(() => { + this.cameraListFn() + }) + } + + nextClickFn() { + // 切换next 次数增加 分辨率遍历 分辨率遍历完 切换摄像头 再次遍历分辨率 调取初始化相机进行改变 + this.clickFrequency++ + if (this.clickFrequency === this.testingFrequency) { + this.Vue = true + this.nextEnabled = false + return + } + let newResolution = this.dealWithResolutionFn(this.resolution) + Logger.info(this.tag, `nextClickFn new Resolution: ${newResolution}`) + this.cameraInit(newResolution[this.clickFrequency]) + this.resolutionSelectVal = String(this.resolution[this.clickFrequency].value) + + } + + // 对分辨率数据处理 获取到需要的格式 + dealWithResolutionFn(arr) { + let newResolution = [] + arr.forEach((item) => { + let indexOf = item.value.indexOf("x") + let objW = Number(item.value.slice(0, indexOf)) + let objH = Number(item.value.slice(indexOf + 1)) + let obj = { + format: 1003, + size: { + "width": objW, + "height": objH + } + } + newResolution.push(obj) + }) + return newResolution + } + + build() { + Column() { + Row() { + Button() { + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({ left: '20vp' }) + }.backgroundColor(Color.Black) + .onClick(() => { + router.back({ + url: 'pages/Camera/Camera_index', + params: { result: 'None', } + }) + }) + + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({ left: '-20vp' }) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceAround, direction: FlexDirection.Column }) { + Column() { + XComponent({ + id: 'componentId', + type: 'surface', + controller: this.mXComponentController + }) + .onLoad(async () => { + Logger.info(this.tag, 'onLoad is called') + // @ts-ignore + this.surfaceId = this.mXComponentController.getXComponentSurfaceId() + Logger.info(this.tag, `onLoad surfaceId: ${this.surfaceId}`) + this.cameraInit() + }) + .size({ width: '100%', height: '100%' }) + Text('Camera Preview').fontSize('20fp').fontColor(Color.White) + }.size({ width: '80%', height: '70%' }) + + Column() { + Row() { + Select(this.resolution) + .selected(this.clickFrequency) + .value(this.resolutionSelectVal) + .font({ size: 16, weight: 500 }) + .fontColor(Color.White) + .selectedOptionBgColor(Color.Black) + .optionBgColor(Color.Black) + .selectedOptionFont({ size: 16, weight: 400 }) + .optionFont({ size: 16, weight: 400 }) + .onSelect((index: number, value) => { + let indexOf = value.indexOf('x') + let objW = Number(value.slice(0, indexOf)) + let objH = Number(value.slice(indexOf + 1)) + let obj = { + format: 1003, + size: { + "width": objW, + "height": objH + } + } + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex, obj) + Logger.info(this.tag, `onSelect Rotation index: ${index}, value: ${value}, obj: ${obj}`) + }) + Select(this.cameraList) + .selected(this.cameraDeviceIndex) + .value(this.cameraDeviceIndex ? 'Camera 1' : 'Camera 0') + .font({ size: 16, weight: 500 }) + .fontColor(Color.White) + .selectedOptionBgColor(Color.Black) + .optionBgColor(Color.Black) + .selectedOptionFont({ size: 16, weight: 400 }) + .optionFont({ size: 16, weight: 400 }) + .onSelect((index: number) => { + this.cameraDeviceIndex = index + this.cameraInit() + }) + }.size({ width: '100%', height: '50%' }).justifyContent(FlexAlign.SpaceEvenly) + + Row() { + Select([{ value: 'YUV' }]) + .selected(0) + .value('YUV') + .font({ size: 16, weight: 500 }) + .fontColor(Color.White) + .selectedOptionBgColor(Color.Black) + .optionBgColor(Color.Black) + .selectedOptionFont({ size: 16, weight: 400 }) + .optionFont({ size: 16, weight: 400 }) + .onSelect((index: number, value) => { + Logger.info(this.tag, `onSelect format index: ${index}, value: ${value}`) + }) + Button('NEXT') + .borderRadius(8) + .backgroundColor(0x317aff) + .enabled(this.nextEnabled) + .opacity(this.nextEnabled ? 1 : 0.4) + .width('20%') + .onClick(async () => { + this.nextClickFn() + }) + }.size({ width: '100%', height: '50%' }).justifyContent(FlexAlign.SpaceEvenly) + }.size({ width: '100%', height: '20%' }) + }.height('80%').width('100%') + + CustomContainer({ + title: this.name, + Url: 'pages/Camera/Camera_index', + StepTips: this.StepTips, + FillColor: $FillColor, + name: $name, + Vue: $Vue, + }).height('10%').width('100%') + }.width('100%').height('100%').backgroundColor(Color.Black) + } +} \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/Camera/CameraSerialPhoto.ets b/validator/acts_validator/src/main/ets/pages/Camera/CameraSerialPhoto.ets new file mode 100644 index 0000000000000000000000000000000000000000..a9617d0b440868becea925fe77cb0f174603a4c8 --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/Camera/CameraSerialPhoto.ets @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2023 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. + */ + +// @ts-ignore +import camera from '@ohos.multimedia.camera' +import Logger from '../model/Logger' +import CameraService from '../model/CameraService' +import { CustomContainer } from '../common/CameraPhotoContainer'; +import FirstDialog from '../model/FirstDialog'; +import router from '@ohos.router'; + +@Entry +@Component +struct cameraOrientation { + @State FillColor: string = '#FF000000'; + @State name: string = 'CameraSerialPhoto'; + @State StepTips: string = '测试目的:用于测试相机连拍\n-左侧显示相机预览窗口\n-右侧显示拍照后的每个图片\n-对于前置摄像头会有镜像效果\n测试步骤:\n1.点击拍照按钮\n预期结果:点击拍照按钮后每个摄像头连拍生成10张图片'; + private tag: string = 'qlw CameraSerialPhoto' + private mXComponentController: XComponentController = new XComponentController() + @State surfaceId: number = 0; + @State cameraDeviceIndex: number = 0 + @State assetUri: string = undefined + @State Vue: boolean = false + @State imageRotation: number = 0 + @State cameraListLength: number = undefined + @State cameraList: SelectOption[] = [] + @State isEnabled: boolean = true + @State takeSelect: number = 0 + @State clickFrequency: number = 0 + @State resolutionSelectVal: string = '' // 下拉框默认value + @State @Watch('onChangeClickSerialPhotoVal') clickSerialPhotoVal: number = 0 + @State timer: number = -1 + + async aboutToAppear() { + await FirstDialog.ChooseDialog(this.StepTips, this.name); + CameraService.setTakePictureCallback(this.handleTakePicture.bind(this)) + } + + onChangeClickSerialPhotoVal() { + if (this.clickSerialPhotoVal < 10 * this.cameraListLength || this.clickSerialPhotoVal == 10 * this.cameraListLength) { + CameraService.takePicture() + this.assetUri = '' + if (this.clickSerialPhotoVal == 10) { + this.onChangeCamera() + } + if (this.clickSerialPhotoVal == 10 * this.cameraListLength){ + clearInterval(this.timer) + this.Vue = true + } + return + } + } + + onChangeCamera(){ + if (this.cameraListLength > 1){ + this.cameraDeviceIndex = Number(!this.cameraDeviceIndex) + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex).then(() => { + this.cameraListFn() + }) + } + } + + cameraListFn() { + this.cameraList = [] + this.cameraListLength = CameraService.cameras.length + for (let index = 0; index < this.cameraListLength; index++) { + this.cameraList.push({ value: `Camera ${index}` }) + } + } + + handleTakePicture = (assetUri: string) => { + this.assetUri = assetUri + Logger.info(this.tag, `takePicture end, assetUri: ${this.assetUri}`) + } + + onPageShow() { + Logger.info(this.tag, `takePicture end, assetUri`) + // @ts-ignore + this.surfaceId = this.mXComponentController.getXComponentSurfaceId() + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex).then(() => { + this.cameraListFn() + }) + } + + onPageHide() { + CameraService.releaseCamera() + Logger.info(this.tag, `onPageHide releaseCamera end`) + } + + build() { + Column() { + Row() { + Button() { + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({ left: '20vp' }) + }.backgroundColor(Color.Black) + .onClick(() => { + router.back({ + url: 'pages/Camera/Camera_index', + params: { result: 'None', } + }) + }) + + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({ left: '-20vp' }) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceAround }) { + Column() { + XComponent({ + id: 'componentId', + type: 'surface', + controller: this.mXComponentController + }) + .onLoad(async () => { + Logger.info(this.tag, 'onLoad is called') + // @ts-ignore + this.surfaceId = this.mXComponentController.getXComponentSurfaceId() + Logger.info(this.tag, `onLoad surfaceId: ${this.surfaceId}`) + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex).then(() => { + this.cameraListFn() + }) + }) + .size({ width: '100%', height: '100%' }) + Text('Camera Preview').fontSize('20fp').fontColor(Color.White) + }.size({ width: '40%', height: '60%' }) + + Column() { + Image(this.assetUri || '').size({ width: '100%', height: '100%' }).border({ width: 1 }) + Text('Oriented Photo').fontSize('20fp').fontColor(Color.White) + }.size({ width: '40%', height: '60%' }) + }.width('100%').height('50%') + + Flex({ direction: FlexDirection.Column }) { + Select(this.cameraList) + .selected(this.cameraDeviceIndex) + .value(this.cameraDeviceIndex ? 'Camera 1' : 'Camera 0') + .font({ size: 16, weight: 500 }) + .fontColor(Color.White) + .selectedOptionBgColor(Color.Black) + .optionBgColor(Color.Black) + .selectedOptionFont({ size: 16, weight: 400 }) + .optionFont({ size: 16, weight: 400 }) + .onSelect((index: number) => { + this.cameraDeviceIndex = index + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex).then(() => { + this.cameraListFn() + }) + }) + Text(`提示:`).fontSize('16fp').fontColor(Color.White) + Text(`期望拍摄${this.cameraListLength*10}张照片,实际拍摄${this.clickSerialPhotoVal}张,如果一致请选择pass,否则选择fail`) + .fontSize('16fp').fontColor(Color.White) + }.size({ width: '80%', height: '25%' }) + + Button('拍照') + .enabled(this.isEnabled) + .opacity(this.isEnabled ? 1 : 0.4) + .width('50%') + .height('5%') + .backgroundColor(0x317aff) + .onClick(async () => { + this.isEnabled = false + this.timer = setInterval(() => { + this.clickSerialPhotoVal++ + }, 1000) + }) + + CustomContainer({ + title: this.name, + Url: 'pages/Camera/Camera_index', + StepTips: this.StepTips, + FillColor: $FillColor, + name: $name, + Vue: $Vue + }).height('10%').width('100%') + }.width('100%').height('100%').backgroundColor(Color.Black) + } +} \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/Camera/CameraVideo.ets b/validator/acts_validator/src/main/ets/pages/Camera/CameraVideo.ets index 40d0495eaf63818accf7da07d4dda86e1f0ae397..9b42113b933469a3c3a8254619af2c886dd11365 100644 --- a/validator/acts_validator/src/main/ets/pages/Camera/CameraVideo.ets +++ b/validator/acts_validator/src/main/ets/pages/Camera/CameraVideo.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Copyright (c) 2023 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 @@ -12,86 +12,261 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +// @ts-ignore import camera from '@ohos.multimedia.camera' import Logger from '../model/Logger' import CameraService from '../model/CameraService' -import {CustomContainer} from '../common/CameraOrientation'; -import FirstDialog from '../model/FirstDialog'; -const CameraMode = { - MODE_PHOTO: 0, // 拍照模式 - MODE_VIDEO: 1 // 录像模式 -} +import { CustomContainer } from '../common/CameraVideoContainer' +import FirstDialog from '../model/FirstDialog' +import router from '@ohos.router' +import mediaPlay from '../model/mediaPlay' +import prompt from '@ohos.prompt' @Entry @Component -struct SetCircle { +struct cameraOrientation { @State FillColor: string = '#FF000000'; @State name: string = 'CameraVideo'; - @State StepTips: string = '测试目的:用于测试相机不同分辨率下的录像能力\n-上边显示录像的预览窗口\n-按下测试按钮后触发3s录像,回放的录像文件将在录像结束后显示在下边窗口\n-使用下拉框可以选择相机设备和分辨率'+'\n'+'预期结果:回放的录像视频与预览窗口的画面一致'; - private tag: string = 'qlw' + @State StepTips: string = '测试目的:用于测试相机录像分辨率能力\n预期结果:所有分辨率均可以录像,录像与预览一致'; + private tag: string = 'qlw CameraVideo' private mXComponentController: XComponentController = new XComponentController() + private mXComponentController1: XComponentController = new XComponentController() @State surfaceId: number = 0; - private x: number = 0; - @State curModel: number = CameraMode.MODE_PHOTO @State cameraDeviceIndex: number = 0 - @State imageRotationValue: number = camera.ImageRotation.ROTATION_90 - @State qualityLevelValue: number = camera.QualityLevel.QUALITY_LEVEL_LOW @State assetUri: string = undefined @State Vue: boolean = false - async aboutToAppear(){ - await FirstDialog.ChooseDialog(this.StepTips,this.name); + @State takeFlag: boolean = true + @State isEnabled: boolean = true + @State resolution: SelectOption[] = [] // 分辨率 + @State clickFrequency: number = 0 // 点击次数 + @State resolutionSelectVal: string = '' // 下拉框默认value + @State cameraListLength: number = undefined // 相机数量 + @State cameraList: SelectOption[] = [] // 相机列表 + @State testingFrequency: number = undefined // 测试总数 + @State testEnabled: boolean = true + @State nextEnabled: boolean = false + + async aboutToAppear() { + await FirstDialog.ChooseDialog(this.StepTips, this.name); } - handleTakePicture = (assetUri: string) => { - this.assetUri = assetUri - Logger.info(this.tag, `Video recorder end, assetUri: ${this.assetUri}`) + + cameraListFn() { + this.cameraList = [] + this.cameraListLength = CameraService.cameras.length + for (let index = 0; index < this.cameraListLength; index++) { + this.cameraList.push({ value: `Camera ${index}` }) + } + // 测试总次数 = 摄像头0的分辨率 + 摄像头1的分辨率 优先以RK为主 + this.testingFrequency = this.resolution.length + Logger.info(this.tag, `testingFrequency ${this.testingFrequency}`) } - @Builder specificNoParam() { - Column() { + nextClickFn() { + // 切换next 次数增加 分辨率遍历 分辨率遍历完 切换摄像头 再次遍历分辨率 调取初始化相机进行改变 + this.clickFrequency++ + + Logger.info(this.tag, `nextClickFn new clickFrequency: ${this.clickFrequency}`) + if (this.clickFrequency === this.testingFrequency) { + this.Vue = true + this.testEnabled = false + this.nextEnabled = false + return } + let newResolution = this.dealWithResolutionFn(this.resolution) + Logger.info(this.tag, `nextClickFn new Resolution: ${newResolution}`) + this.cameraInit(newResolution[this.clickFrequency]) + this.resolutionSelectVal = String(this.resolution[this.clickFrequency].value) + + } + // 对分辨率数据处理 获取到需要的格式 + dealWithResolutionFn(arr) { + let newResolution = [] + arr.forEach((item) => { + let indexOf = item.value.indexOf("x") + let objW = Number(item.value.slice(0, indexOf)) + let objH = Number(item.value.slice(indexOf + 1)) + let obj = { + format: 1003, + size: { + "width": objW, + "height": objH + } + } + newResolution.push(obj) + }) + return newResolution } + + async cameraInit(obj?) { + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex, obj).then(() => { + this.resolution = CameraService.resolution + this.resolutionSelectVal = String(this.resolution[this.clickFrequency].value) + this.cameraListFn() + }) + } + + onPageShow() { + Logger.info(this.tag, `takePicture end, assetUri`) + // @ts-ignore + this.surfaceId = this.mXComponentController.getXComponentSurfaceId() + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex) + } + + onPageHide() { + CameraService.releaseCamera() + Logger.info(this.tag, `onPageHide releaseCamera end`) + } + build() { Column() { + Row() { + Button() { + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({ left: '20vp' }) + }.backgroundColor(Color.Black) + .onClick(() => { + router.back({ + url: 'pages/Camera/Camera_index', + params: { result: 'None', } + }) + }) + + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({ left: '-20vp' }) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + + Flex({ justifyContent: FlexAlign.SpaceEvenly }) { + + Column() { + XComponent({ + id: 'componentId', + type: 'surface', + controller: this.mXComponentController + }) + .onLoad(async () => { + Logger.info(this.tag, 'onLoad is called') + // @ts-ignore + this.surfaceId = this.mXComponentController.getXComponentSurfaceId() + Logger.info(this.tag, `onLoad surfaceId: ${this.surfaceId}`) + this.cameraInit() + }) + .size({ width: '100%', height: '100%' }) + Text('Video capture').fontSize('20fp').fontColor(Color.White) + }.size({ width: '45%', height: '100%' }) + + Column() { + XComponent({ + id: '', + type: 'surface', + controller: this.mXComponentController1 + }) + .onLoad(() => { + }) + .size({ width: '100%', height: '100%' }) + Text('Video callback').fontSize('20fp').fontColor(Color.White) + }.size({ width: '45%', height: '100%' }) + + }.size({ width: '100%', height: '50%' }) + + Column() { + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceEvenly }) { + Select(this.resolution) + .selected(this.clickFrequency) + .value(this.resolutionSelectVal) + .font({ size: 16, weight: 500 }) + .fontColor(Color.White) + .margin({ top: 50 }) + .selectedOptionBgColor(Color.Black) + .optionBgColor(Color.Black) + .selectedOptionFont({ size: 16, weight: 400 }) + .optionFont({ size: 16, weight: 400 }) + .onSelect((index: number, value) => { + let indexOf = value.indexOf('x') + let objW = Number(value.slice(0, indexOf)) + let objH = Number(value.slice(indexOf + 1)) + let obj = { + format: 1003, + size: { + "width": objW, + "height": objH + } + } + CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex, obj) + Logger.info(this.tag, `onSelect Rotation index: ${index}, value: ${value}, obj: ${obj}`) + }) + Select(this.cameraList) + .selected(this.cameraDeviceIndex) + .value(this.cameraDeviceIndex ? 'Camera 1' : 'Camera 0') + .font({ size: 16, weight: 500 }) + .fontColor(Color.White) + .margin({ top: 50 }) + .selectedOptionBgColor(Color.Black) + .optionBgColor(Color.Black) + .selectedOptionFont({ size: 16, weight: 400 }) + .optionFont({ size: 16, weight: 400 }) + .onSelect((index: number) => { + this.cameraDeviceIndex = index + this.cameraInit() + }) + Select([{ value: 'YUV' }]) + .selected(0) + .value('YUV') + .font({ size: 16, weight: 500 }) + .fontColor(Color.White) + .margin({ top: 50 }) + .selectedOptionBgColor(Color.Black) + .optionBgColor(Color.Black) + .selectedOptionFont({ size: 16, weight: 400 }) + .optionFont({ size: 16, weight: 400 }) + .onSelect((index: number, value) => { + Logger.info(this.tag, `onSelect format index: ${index}, value: ${value}`) + }) + }.size({ width: '100%', height: '50%' }) + + Row() { + Button('TEST') + .borderRadius(8) + .backgroundColor(0x317aff) + .margin(15) + .enabled(this.testEnabled) + .opacity(this.testEnabled ? 1 : 0.4) + .size({ width: '30%', height: '40%' }) + .onClick(async () => { + this.testEnabled = false + this.nextEnabled = true + prompt.showToast({ + message: '录制中,请等待三秒', duration: 1000 + }); + CameraService.startVideo().then(() => { + setTimeout(() => { + // @ts-ignore + let sufferID = this.mXComponentController1.getXComponentSurfaceId() + Logger.info(this.tag, `onSelect format sufferID: ${sufferID}`) + mediaPlay.init(sufferID) + }, 4000) + }) + }) + Button('NEXT') + .borderRadius(8) + .backgroundColor(0x317aff) + .margin(15) + .enabled(this.nextEnabled) + .opacity(this.nextEnabled ? 1 : 0.4) + .size({ width: '30%', height: '40%' }) + .onClick(async () => { + this.testEnabled = true + this.nextClickFn() + }) + }.size({ width: '100%', height: '50%' }).justifyContent(FlexAlign.SpaceEvenly) + }.size({ width: '100%', height: '30%' }) + CustomContainer({ title: this.name, - Url:'pages/Camera/Camera_index', - StepTips:this.StepTips, - content: this.specificNoParam, - FillColor:$FillColor, + Url: 'pages/Camera/Camera_index', + StepTips: this.StepTips, + FillColor: $FillColor, name: $name, - Vue: $Vue - }).height('30%').width('100%') - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) { - XComponent({ - id: 'componentId', - type: 'surface', - controller: this.mXComponentController - }) - .onLoad(async () => { - Logger.info(this.tag, 'onLoad is called') - // @ts-ignore - this.mXComponentController.setXComponentSurfaceSize({ surfaceWidth: 10, surfaceHeight: 10 }) - // @ts-ignore - this.surfaceId = this.mXComponentController.getXComponentSurfaceId() - Logger.info(this.tag, `onLoad surfaceId: ${this.surfaceId}`) - this.curModel = CameraMode.MODE_PHOTO - CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex) - }) - .height('40%') - .width('40%') - Text('Camera Preview').fontSize('20fp') -// Video() - Text('Video playback').fontSize('20fp') - Button('Test', { - type: ButtonType.Normal, - stateEffect: true - }).borderRadius(8).backgroundColor(0x317aff).width('20%').onClick(() => { - CameraService.startVideo() - CameraService.setTakePictureCallback(this.handleTakePicture.bind(this)) - this.Vue = true - }) - }.width('100%').height('70%').backgroundColor(Color.White) + Vue: $Vue, + }).height('10%').width('100%') }.width('100%').height('100%').backgroundColor(Color.Black) } } \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/Camera/Camera_index.ets b/validator/acts_validator/src/main/ets/pages/Camera/Camera_index.ets index e011a2aefd03d2f8b3dd88e69e223bd2efdf1ac5..96495eac02966cec9f450dae85b155ec6d531317 100644 --- a/validator/acts_validator/src/main/ets/pages/Camera/Camera_index.ets +++ b/validator/acts_validator/src/main/ets/pages/Camera/Camera_index.ets @@ -39,9 +39,12 @@ struct IndexPage { @State result : string = ''; @State TEST : number = 0; private TestCaseList = [ - {title:'Camera Orientation',uri:'pages/Camera/CameraOrientation'}, - {title:'Camera Format',uri:'pages/Camera/CameraFormat'}, - {title:'Camera Video',uri:'pages/Camera/CameraVideo'}, + { title: 'CameraPreviewFormat', uri: 'pages/Camera/CameraPreviewFormat' }, + { title: 'CameraPhotoFormat', uri: 'pages/Camera/CameraPhotoFormat' }, + { title: 'CameraOrientation', uri: 'pages/Camera/CameraOrientation' }, + { title: 'CameraSerialPhoto', uri: 'pages/Camera/CameraSerialPhoto' }, + { title: 'CameraVideo', uri: 'pages/Camera/CameraVideo' }, + { title: 'CameraFlash', uri: 'pages/Camera/CameraFlash' }, ] @State ColorObject : string[] = VarColor; async onPageShow(){ diff --git a/validator/acts_validator/src/main/ets/pages/Player/PlayAudio.ets b/validator/acts_validator/src/main/ets/pages/Player/PlayAudio.ets new file mode 100644 index 0000000000000000000000000000000000000000..7cccbc279f9dcef7e5a80ae611bb9d2a6153843f --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/Player/PlayAudio.ets @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 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 { CustomContainer } from '../common/AudioContainer'; +import FirstDialog from '../model/FirstDialog'; +import router from '@ohos.router'; + +@Entry +@Component +struct playAudio { + @State FillColor: string = '#FF000000'; + @State name: string = 'PlayAudio'; + @State StepTips: string = '测试目的:用于测试音频播放暂停seek\n预期结果:音频播放暂停seek功能正常'; + private tag: string = 'qlw' + @State Vue: boolean = false + @State videoSrc: Resource = $rawfile('StarWars10s-1C-44100-2SW.wav') + @State isAutoPlay: boolean = true + @State showControls: boolean = true + controller: VideoController = new VideoController() + + async aboutToAppear() { + await FirstDialog.ChooseDialog(this.StepTips, this.name); + } + + build() { + Column() { + Row() { + Button() { + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({ left: '20vp' }) + }.backgroundColor(Color.Black) + .onClick(() => { + router.back({ + url: 'pages/Player/Player_index', + params: { result: 'None', } + }) + }) + + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({ left: '-20vp' }) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Video({ + src: this.videoSrc, + controller: this.controller + }) + .width('100%') + .height('60%') + .autoPlay(this.isAutoPlay) + .controls(this.showControls) + .onFinish(() => { + this.Vue = true + }) + }.width('100%').height('80%').onClick(() => { + this.showControls = !this.showControls + }) + + CustomContainer({ + title: this.name, + Url: 'pages/Player/Player_index', + StepTips: this.StepTips, + name: $name, + Vue: $Vue + }).height('10%').width('100%') + }.width('100%').height('100%').backgroundColor(Color.Black) + } +} \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/Player/PlayVideo.ets b/validator/acts_validator/src/main/ets/pages/Player/PlayVideo.ets new file mode 100644 index 0000000000000000000000000000000000000000..385e6ef912c81376b3ed314e15ffc2a17ba0aca1 --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/Player/PlayVideo.ets @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2023 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 { CustomContainer } from '../common/AudioContainer'; +import FirstDialog from '../model/FirstDialog'; +import router from '@ohos.router'; + +@Entry +@Component +struct playVideo { + @State FillColor: string = '#FF000000'; + @State name: string = 'PlayVideo'; + @State StepTips: string = '测试目的:用于测试视频播放暂停seek\n预期结果:视频播放暂停seek功能正常'; + private tag: string = 'qlw' + @State Vue: boolean = false + @State videoSrc: Resource = $rawfile('H264_AAC.mkv') + @State isAutoPlay: boolean = true + @State showControls: boolean = true + controller: VideoController = new VideoController() + + async aboutToAppear() { + await FirstDialog.ChooseDialog(this.StepTips, this.name); + } + + build() { + Column() { + Row() { + Button() { + Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({ left: '20vp' }) + }.backgroundColor(Color.Black) + .onClick(() => { + router.back({ + url: 'pages/Player/Player_index', + params: { result: 'None', } + }) + }) + + Text(this.name).fontColor(Color.White).fontSize('18fp').margin({ left: '-20vp' }) + Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) + }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) + + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Video({ + src: this.videoSrc, + controller: this.controller + }) + .width('100%') + .height('60%') + .autoPlay(this.isAutoPlay) + .controls(this.showControls) + .onFinish(() => { + this.Vue = true + }) + }.width('100%').height('80%').onClick(() => { + this.showControls = !this.showControls + }) + + CustomContainer({ + title: this.name, + Url: 'pages/Player/Player_index', + StepTips: this.StepTips, + name: $name, + Vue: $Vue + }).height('10%').width('100%') + }.width('100%').height('100%').backgroundColor(Color.Black) + } +} \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/Player/Player_index.ets b/validator/acts_validator/src/main/ets/pages/Player/Player_index.ets index 3763ad6686687ec78c337f04a9a88b9b20722602..23730f79329de64308a5c33f4b3c94023be35684 100644 --- a/validator/acts_validator/src/main/ets/pages/Player/Player_index.ets +++ b/validator/acts_validator/src/main/ets/pages/Player/Player_index.ets @@ -39,7 +39,8 @@ struct IndexPage { @State result : string = ''; @State TEST : number = 0; private TestCaseList = [ - {title:'ScrollingList',uri:'pages/Player/ScrollListTest'}, + {title:'PlayAudio',uri:'pages/Player/PlayAudio'}, + {title:'PlayVideo',uri:'pages/Player/PlayVideo'}, ] @State ColorObject : string[] = VarColor; async onPageShow(){ diff --git a/validator/acts_validator/src/main/ets/pages/Player/ScrollListTest.ets b/validator/acts_validator/src/main/ets/pages/Player/ScrollListTest.ets deleted file mode 100644 index 2f96aadfdc32f3960a7a1ac012452febbc55e71a..0000000000000000000000000000000000000000 --- a/validator/acts_validator/src/main/ets/pages/Player/ScrollListTest.ets +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 {CustomContainer} from '../common/CustomContainer'; -import FirstDialog from '../model/FirstDialog'; -@Entry -@Component -struct CustomContainerUser { - private listArr: number[] = Array.from(new Array(50).keys()); - @State name: string = 'ScrollingList'; - @State StepTips: string = '操作步骤:滑动列表观察是否能正常滑动'+'\n'+'预期结果:列表滑动正常'; - @State Vue: boolean = false; - async aboutToAppear(){ - await FirstDialog.ChooseDialog(this.StepTips,this.name); - this.Vue = true; - } - @Builder specificNoParam() { - Column() { - List() { - ForEach(this.listArr,(item:any,index:number) => { - ListItem() { - Text('Item #' + (index + 1)).width('100%').height(50).fontSize(16).fontColor(Color.White).margin({left:'10vp'}) - } - },index => index) - }.height('100%').width('100%').divider({strokeWidth:1,color:Color.Grey}) - }.height('83%').width('100%') - } - build() { - Column() { - CustomContainer({ - title: this.name, - Url: 'pages/Player/Player_index', - StepTips: this.StepTips, - content: this.specificNoParam.bind(this), - name: $name, - Vue: $Vue, - }) - }.width('100%').height('100%').backgroundColor(Color.Black) - } -} diff --git a/validator/acts_validator/src/main/ets/pages/common/AudioContainer.ets b/validator/acts_validator/src/main/ets/pages/common/AudioContainer.ets new file mode 100644 index 0000000000000000000000000000000000000000..630818f5164a81589296b309d92e4884f9bbeed5 --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/common/AudioContainer.ets @@ -0,0 +1,148 @@ +/* + * 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 prompt from '@ohos.prompt'; +import fileio from '@ohos.fileio'; +import router from '@ohos.router'; +// @ts-ignore +import screenshot from '@ohos.screenshot'; +import image from '@ohos.multimedia.image'; +import Logger from '../model/Logger'; +import mediaLibrary from '@ohos.multimedia.mediaLibrary'; + +let path = globalThis.dir; + +const TAG = '[Screenshot]'; +@Component +export struct CustomContainer { + @Link name : string; + title : string = ''; + StepTips: string = ''; + Url : string = ''; + @Link Vue : boolean; + @Builder + PassBtn(text: Resource, isFullScreen: boolean) { + if(this.Vue == false){ + Button({stateEffect:this.Vue}) { + Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey).opacity(0.4) + .onClick(()=>{ + + }) + } + else{ + Button({stateEffect:this.Vue}) { + Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(()=>{ + router.back({ + url:this.Url, + params: {result : 'Pass', title : this.name, + } + }) + this.getScreen(isFullScreen); + prompt.showToast({ + message: '通过', duration: 1000 + }); + }) + } + } + @Builder + FailBtn(text: Resource, isFullScreen: boolean) { + Button(){ + Image($r('app.media.ic_public_fail')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(()=>{ + router.back({ + url:this.Url, + params: {result : 'Fail',title : this.name, + } + }) + this.getScreen(isFullScreen); + prompt.showToast({ + message: '失败', duration: 1000 + }); + }) + } + build() { + Column() { + Row() { + this.PassBtn($r('app.string.btn_fullscreen'), true); + Button(){ + Image($r('app.media.ic_public_help')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(() =>{ + AlertDialog.show({ + title:'操作提示', + message: this.StepTips, + confirm:{ + value:'OK', + action:()=>{ + } + } + }) + }) + this.FailBtn($r('app.string.btn_fullscreen'), true); + }.width('100%').justifyContent(FlexAlign.SpaceEvenly).backgroundColor(Color.Black) + }.height('98%').width('100%') + } + async savePicture(data: image.PixelMap, context: any) { + Logger.info(TAG, `savePicture`); + let packOpts: image.PackingOption = { + format: "image/jpeg", quality: 100 + }; + let info = { + prefix: 'IMG_', suffix: '.jpg', directory: mediaLibrary.DirectoryType.DIR_IMAGE + }; + let name = this.name; + let displayName = `${info.prefix}${name}${info.suffix}`; + let dirPath = path + '/' + displayName; + let imagePackerApi = image.createImagePacker(); + let arrayBuffer = await imagePackerApi.packing(data, packOpts); + let fd = fileio.openSync(dirPath,0o102,0o666); + imagePackerApi.release(); + try { + await fileio.write(fd, arrayBuffer); + } catch (err) { + Logger.error(`write failed, code is ${err.code}, message is ${err.message}`); + } + await fileio.close(fd); + Logger.info(TAG, `write done`); + + } + getScreen = (isFullScreen: boolean) => { + let screenshotOptions: screenshot.ScreenshotOptions = { + screenRect: { left: 0, top: 0, width: 400, height: 400 }, + imageSize: { width: 400, height: 400 }, + rotation: 0, + displayId: 0 + }; + if (isFullScreen) { + screenshotOptions = { + rotation: 0 + } + } + try { + screenshot.save(screenshotOptions, (err, data: image.PixelMap) => { + if (err) { + Logger.info(TAG, `Failed to save the screenshot. Error:${JSON.stringify(err)}`); + } + Logger.info(TAG, 'save callback'); + this.savePicture(data, getContext(this) as any); + }) + } catch (err) { + Logger.error(`save failed, code is ${err.code}, message is ${err.message}`); + } + } +} diff --git a/validator/acts_validator/src/main/ets/pages/common/CameraFlashContainer.ets b/validator/acts_validator/src/main/ets/pages/common/CameraFlashContainer.ets new file mode 100644 index 0000000000000000000000000000000000000000..8e72e005df1e8cfd17237b43c4d867119b2932c3 --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/common/CameraFlashContainer.ets @@ -0,0 +1,164 @@ +/* + * 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 fileio from '@ohos.fileio'; +import prompt from '@ohos.prompt'; +import router from '@ohos.router'; +// @ts-ignore +import screenshot from '@ohos.screenshot'; +import image from '@ohos.multimedia.image'; +import Logger from '../model/Logger'; +import mediaLibrary from '@ohos.multimedia.mediaLibrary'; + +let path = globalThis.dir; +const TAG = '[Screenshot]'; + +@Component +export struct CustomContainer { + @Link FillColor: string; + @Link name: string; + @Link Vue: boolean; + @Link isFlash: boolean; + Url: string = ''; + title: string = ''; + StepTips: string = ''; + + @Builder + PassBtn(text: Resource, isFullScreen: boolean) { + if (this.Vue == false) { + Button({ stateEffect: this.Vue }) { + Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') + } + .width('30%') + .height('30vp') + .backgroundColor(Color.Grey) + .opacity(0.4) + .onClick(() => { + + }) + } + else { + Button({ stateEffect: this.Vue }) { + Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(() => { + router.back({ + url: this.Url, + params: { result: 'Pass', title: this.name, + } + }) + this.getScreen(isFullScreen); + prompt.showToast({ + message: '通过', duration: 1000 + }); + }) + } + } + + @Builder + FailBtn(text: Resource, isFullScreen: boolean) { + Button() { + Image($r('app.media.ic_public_fail')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(() => { + router.back({ + url: this.Url, + params: { result: 'Fail', title: this.name, + } + }) + this.getScreen(isFullScreen); + prompt.showToast({ + message: '失败', duration: 1000 + }); + }) + } + + build() { + Column() { + Flex({ + justifyContent: FlexAlign.SpaceEvenly, alignItems: ItemAlign.Center + }) { + this.PassBtn($r('app.string.btn_fullscreen'), true); + Button() { + Image($r('app.media.ic_public_help')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(() => { + AlertDialog.show( + { + title: '操作提示', + message: this.StepTips, + confirm: { + value: 'OK', + action: () => { + } + } + } + ) + }) + + this.FailBtn($r('app.string.btn_fullscreen'), true); + }.height('98%').width('100%').backgroundColor(Color.Black) + }.height('98%').width('100%') + } + + async savePicture(data: image.PixelMap, context: any) { + Logger.info(TAG, `savePicture`); + let packOpts: image.PackingOption = { + format: "image/jpeg", quality: 100 + }; + let info = { + prefix: 'IMG_', suffix: '.jpg', directory: mediaLibrary.DirectoryType.DIR_IMAGE + }; + let name = this.name; + let displayName = `${info.prefix}${name}${info.suffix}`; + let dirPath = path + '/' + displayName; + let imagePackerApi = image.createImagePacker(); + let arrayBuffer = await imagePackerApi.packing(data, packOpts); + let fd = fileio.openSync(dirPath, 0o102, 0o666); + imagePackerApi.release(); + try { + await fileio.write(fd, arrayBuffer); + } catch (err) { + Logger.error(`write failed, code is ${err.code}, message is ${err.message}`); + } + await fileio.close(fd); + Logger.info(TAG, `write done`); + } + + getScreen = (isFullScreen: boolean) => { + let screenshotOptions: screenshot.ScreenshotOptions = { + screenRect: { left: 0, top: 0, width: 400, height: 400 }, + imageSize: { width: 400, height: 400 }, + rotation: 0, + displayId: 0 + }; + if (isFullScreen) { + screenshotOptions = { + rotation: 0 + } + } + try { + screenshot.save(screenshotOptions, (err, data: image.PixelMap) => { + if (err) { + Logger.info(TAG, `Failed to save the screenshot. Error:${JSON.stringify(err)}`); + } + Logger.info(TAG, 'save callback'); + this.savePicture(data, getContext(this) as any); + }) + } catch (err) { + Logger.error(`save failed, code is ${err.code}, message is ${err.message}`); + } + } +} diff --git a/validator/acts_validator/src/main/ets/pages/common/CameraOrientationContainer.ets b/validator/acts_validator/src/main/ets/pages/common/CameraOrientationContainer.ets new file mode 100644 index 0000000000000000000000000000000000000000..25b62cc5771ff9a46a1c8e47ae1ebb30ba1d4ff9 --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/common/CameraOrientationContainer.ets @@ -0,0 +1,161 @@ +/* + * 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 fileio from '@ohos.fileio'; +import prompt from '@ohos.prompt'; +import router from '@ohos.router'; +// @ts-ignore +import screenshot from '@ohos.screenshot'; +import image from '@ohos.multimedia.image'; +import Logger from '../model/Logger'; +import mediaLibrary from '@ohos.multimedia.mediaLibrary'; + +let path = globalThis.dir; +const TAG = '[Screenshot]'; +@Component +export struct CustomContainer { + @Link FillColor: string; + @Link name: string; + @Link Vue : boolean; + @Link isEnabled: boolean; + Url : string = ''; + title : string = ''; + StepTips: string = ''; + testingFrequency: number + @Link clickFrequency: number + @Builder + PassBtn(text: Resource, isFullScreen: boolean) { + if(this.Vue == false){ + Button({stateEffect:this.Vue}) { + Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey).opacity(0.4) + .onClick(()=>{ + + }) + } + else{ + Button({stateEffect:this.Vue}) { + Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(()=>{ + this.isEnabled = true + this.Vue = false + this.clickFrequency++ + if (this.clickFrequency === this.testingFrequency){ + router.back({ + url:this.Url, + params: {result : 'Pass', title : this.name, + } + }) + } + this.getScreen(isFullScreen); + prompt.showToast({ + message: '通过', duration: 1000 + }); + }) + } + } + @Builder + FailBtn(text: Resource, isFullScreen: boolean) { + Button(){ + Image($r('app.media.ic_public_fail')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(()=>{ + router.back({ + url:this.Url, + params: {result : 'Fail',title : this.name, + } + }) + this.getScreen(isFullScreen); + prompt.showToast({ + message: '失败', duration: 1000 + }); + }) + } + build() { + Column() { + Flex({ + justifyContent: FlexAlign.SpaceEvenly, alignItems: ItemAlign.Center + }){ + this.PassBtn($r('app.string.btn_fullscreen'), true); + Button(){ + Image($r('app.media.ic_public_help')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(() =>{ + AlertDialog.show( + { + title:'操作提示', + message: this.StepTips, + confirm:{ + value:'OK', + action:()=>{ + } + } + } + ) + }) + this.FailBtn($r('app.string.btn_fullscreen'), true); + }.height('98%').width('100%').backgroundColor(Color.Black) + }.height('98%').width('100%') + } + + async savePicture(data: image.PixelMap, context: any) { + Logger.info(TAG, `savePicture`); + let packOpts: image.PackingOption = { + format: "image/jpeg", quality: 100 + }; + let info = { + prefix: 'IMG_', suffix: '.jpg', directory: mediaLibrary.DirectoryType.DIR_IMAGE + }; + let name = this.name; + let displayName = `${info.prefix}${name}${info.suffix}`; + let dirPath = path + '/' + displayName; + let imagePackerApi = image.createImagePacker(); + let arrayBuffer = await imagePackerApi.packing(data, packOpts); + let fd = fileio.openSync(dirPath,0o102,0o666); + imagePackerApi.release(); + try { + await fileio.write(fd, arrayBuffer); + } catch (err) { + Logger.error(`write failed, code is ${err.code}, message is ${err.message}`); + } + await fileio.close(fd); + Logger.info(TAG, `write done`); + } + getScreen = (isFullScreen: boolean) => { + let screenshotOptions: screenshot.ScreenshotOptions = { + screenRect: { left: 0, top: 0, width: 400, height: 400 }, + imageSize: { width: 400, height: 400 }, + rotation: 0, + displayId: 0 + }; + if (isFullScreen) { + screenshotOptions = { + rotation: 0 + } + } + try { + screenshot.save(screenshotOptions, (err, data: image.PixelMap) => { + if (err) { + Logger.info(TAG, `Failed to save the screenshot. Error:${JSON.stringify(err)}`); + } + Logger.info(TAG, 'save callback'); + this.savePicture(data, getContext(this) as any); + }) + } catch (err) { + Logger.error(`save failed, code is ${err.code}, message is ${err.message}`); + } + } +} diff --git a/validator/acts_validator/src/main/ets/pages/common/CameraOrientation.ets b/validator/acts_validator/src/main/ets/pages/common/CameraPhotoContainer.ets similarity index 81% rename from validator/acts_validator/src/main/ets/pages/common/CameraOrientation.ets rename to validator/acts_validator/src/main/ets/pages/common/CameraPhotoContainer.ets index ebef726e687419b0c1874639b97fb57721bf1b10..46c0812e0128dddab83a8b1609b40691a2aa40ee 100644 --- a/validator/acts_validator/src/main/ets/pages/common/CameraOrientation.ets +++ b/validator/acts_validator/src/main/ets/pages/common/CameraPhotoContainer.ets @@ -1,165 +1,153 @@ -/* - * Copyright (c) 2022-2023 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 fileio from '@ohos.fileio'; -import prompt from '@ohos.prompt'; -import router from '@ohos.router'; -import screenshot from '@ohos.screenshot'; -import image from '@ohos.multimedia.image'; -import Logger from '../model/Logger'; -import mediaLibrary from '@ohos.multimedia.mediaLibrary'; - -let path = globalThis.dir; -const TAG = '[Screenshot]'; -@Component -export struct CustomContainer { - @Link FillColor: string; - @Link name: string; - @Link Vue : boolean; - Url : string = ''; - title : string = ''; - StepTips: string = ''; - @BuilderParam content: () => void; - @Builder - PassBtn(text: Resource, isFullScreen: boolean) { - if(this.Vue == false){ - Button({stateEffect:this.Vue}) { - Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') - }.width('30%').height('30vp').backgroundColor(Color.Grey).opacity(0.4) - .onClick(()=>{ - - }) - } - else{ - Button({stateEffect:this.Vue}) { - Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') - }.width('30%').height('30vp').backgroundColor(Color.Grey) - .onClick(()=>{ - router.back({ - url:this.Url, - params: {result : 'Pass', title : this.name, - } - }) - this.getScreen(isFullScreen); - prompt.showToast({ - message: '通过', duration: 1000 - }); - }) - } - } - @Builder - FailBtn(text: Resource, isFullScreen: boolean) { - Button(){ - Image($r('app.media.ic_public_fail')).width('20vp').height('20vp') - }.width('30%').height('30vp').backgroundColor(Color.Grey) - .onClick(()=>{ - router.back({ - url:this.Url, - params: {result : 'Fail',title : this.name, - } - }) - this.getScreen(isFullScreen); - prompt.showToast({ - message: '失败', duration: 1000 - }); - }) - } - build() { - Column() { - Row() { - Button(){ - Image($r('app.media.ic_public_back')).width('20vp').height('18vp').margin({left:'20vp'}) - }.backgroundColor(Color.Black) - .onClick(()=>{ - router.back({ - url:this.Url, - params: {result : 'None',} - }) - }) - Text(this.title).fontColor(Color.White).fontSize('18fp').margin({left:'-20vp'}) - Text('hello').fontColor(Color.White).visibility(Visibility.Hidden) - }.backgroundColor(Color.Black).height('10%').width('100%').justifyContent(FlexAlign.SpaceBetween) - this.content(); - Blank() - Row() { - this.PassBtn($r('app.string.btn_fullscreen'), true); - Button(){ - Image($r('app.media.ic_public_help')).width('20vp').height('20vp') - }.width('30%').height('30vp').backgroundColor(Color.Grey) - .onClick(() =>{ - AlertDialog.show( - { - title:'操作提示', - message: this.StepTips, - confirm:{ - value:'OK', - action:()=>{ - } - } - } - ) - }) - this.FailBtn($r('app.string.btn_fullscreen'), true); - }.width('100%').justifyContent(FlexAlign.SpaceEvenly).backgroundColor(Color.Black) - }.height('98%').width('100%') - } - async savePicture(data: image.PixelMap, context: any) { - Logger.info(TAG, `savePicture`); - let packOpts: image.PackingOption = { - format: "image/jpeg", quality: 100 - }; - let info = { - prefix: 'IMG_', suffix: '.jpg', directory: mediaLibrary.DirectoryType.DIR_IMAGE - }; - let name = this.name; - let displayName = `${info.prefix}${name}${info.suffix}`; - let dirPath = path + '/screenshot' + '/' + displayName; - let imagePackerApi = image.createImagePacker(); - let arrayBuffer = await imagePackerApi.packing(data, packOpts); - let fd = fileio.openSync(dirPath,0o102,0o666); - imagePackerApi.release(); - try { - await fileio.write(fd, arrayBuffer); - } catch (err) { - Logger.error(`write failed, code is ${err.code}, message is ${err.message}`); - } - await fileio.close(fd); - Logger.info(TAG, `write done`); - } - getScreen = (isFullScreen: boolean) => { - let screenshotOptions: screenshot.ScreenshotOptions = { - screenRect: { left: 0, top: 0, width: 400, height: 400 }, - imageSize: { width: 400, height: 400 }, - rotation: 0, - displayId: 0 - }; - if (isFullScreen) { - screenshotOptions = { - rotation: 0 - } - } - try { - screenshot.save(screenshotOptions, (err, data: image.PixelMap) => { - if (err) { - Logger.info(TAG, `Failed to save the screenshot. Error:${JSON.stringify(err)}`); - } - Logger.info(TAG, 'save callback'); - this.savePicture(data, getContext(this) as any); - }) - } catch (err) { - Logger.error(`save failed, code is ${err.code}, message is ${err.message}`); - } - } -} +/* + * 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 fileio from '@ohos.fileio'; +import prompt from '@ohos.prompt'; +import router from '@ohos.router'; +// @ts-ignore +import screenshot from '@ohos.screenshot'; +import image from '@ohos.multimedia.image'; +import Logger from '../model/Logger'; +import mediaLibrary from '@ohos.multimedia.mediaLibrary'; + +let path = globalThis.dir; +const TAG = '[Screenshot]'; +@Component +export struct CustomContainer { + @Link FillColor: string; + @Link name: string; + @Link Vue : boolean; + Url : string = ''; + title : string = ''; + StepTips: string = ''; + @Builder + PassBtn(text: Resource, isFullScreen: boolean) { + if(this.Vue == false){ + Button({stateEffect:this.Vue}) { + Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey).opacity(0.4) + .onClick(()=>{ + + }) + } + else{ + Button({stateEffect:this.Vue}) { + Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(()=>{ + router.back({ + url:this.Url, + params: {result : 'Pass', title : this.name, + } + }) + this.getScreen(isFullScreen); + prompt.showToast({ + message: '通过', duration: 1000 + }); + }) + } + } + @Builder + FailBtn(text: Resource, isFullScreen: boolean) { + Button(){ + Image($r('app.media.ic_public_fail')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(()=>{ + router.back({ + url:this.Url, + params: {result : 'Fail',title : this.name, + } + }) + this.getScreen(isFullScreen); + prompt.showToast({ + message: '失败', duration: 1000 + }); + }) + } + build() { + Column() { + Flex({ + justifyContent: FlexAlign.SpaceEvenly, alignItems: ItemAlign.Center + }){ + this.PassBtn($r('app.string.btn_fullscreen'), true); + Button(){ + Image($r('app.media.ic_public_help')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(() =>{ + AlertDialog.show( + { + title:'操作提示', + message: this.StepTips, + confirm:{ + value:'OK', + action:()=>{ + } + } + } + ) + }) + this.FailBtn($r('app.string.btn_fullscreen'), true); + }.height('98%').width('100%').backgroundColor(Color.Black) + }.height('98%').width('100%') + } + + async savePicture(data: image.PixelMap, context: any) { + Logger.info(TAG, `savePicture`); + let packOpts: image.PackingOption = { + format: "image/jpeg", quality: 100 + }; + let info = { + prefix: 'IMG_', suffix: '.jpg', directory: mediaLibrary.DirectoryType.DIR_IMAGE + }; + let name = this.name; + let displayName = `${info.prefix}${name}${info.suffix}`; + let dirPath = path + '/' + displayName; + let imagePackerApi = image.createImagePacker(); + let arrayBuffer = await imagePackerApi.packing(data, packOpts); + let fd = fileio.openSync(dirPath,0o102,0o666); + imagePackerApi.release(); + try { + await fileio.write(fd, arrayBuffer); + } catch (err) { + Logger.error(`write failed, code is ${err.code}, message is ${err.message}`); + } + await fileio.close(fd); + Logger.info(TAG, `write done`); + } + getScreen = (isFullScreen: boolean) => { + let screenshotOptions: screenshot.ScreenshotOptions = { + screenRect: { left: 0, top: 0, width: 400, height: 400 }, + imageSize: { width: 400, height: 400 }, + rotation: 0, + displayId: 0 + }; + if (isFullScreen) { + screenshotOptions = { + rotation: 0 + } + } + try { + screenshot.save(screenshotOptions, (err, data: image.PixelMap) => { + if (err) { + Logger.info(TAG, `Failed to save the screenshot. Error:${JSON.stringify(err)}`); + } + Logger.info(TAG, 'save callback'); + this.savePicture(data, getContext(this) as any); + }) + } catch (err) { + Logger.error(`save failed, code is ${err.code}, message is ${err.message}`); + } + } +} diff --git a/validator/acts_validator/src/main/ets/pages/common/CameraPreviewFormatContainer.ets b/validator/acts_validator/src/main/ets/pages/common/CameraPreviewFormatContainer.ets new file mode 100644 index 0000000000000000000000000000000000000000..46c0812e0128dddab83a8b1609b40691a2aa40ee --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/common/CameraPreviewFormatContainer.ets @@ -0,0 +1,153 @@ +/* + * 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 fileio from '@ohos.fileio'; +import prompt from '@ohos.prompt'; +import router from '@ohos.router'; +// @ts-ignore +import screenshot from '@ohos.screenshot'; +import image from '@ohos.multimedia.image'; +import Logger from '../model/Logger'; +import mediaLibrary from '@ohos.multimedia.mediaLibrary'; + +let path = globalThis.dir; +const TAG = '[Screenshot]'; +@Component +export struct CustomContainer { + @Link FillColor: string; + @Link name: string; + @Link Vue : boolean; + Url : string = ''; + title : string = ''; + StepTips: string = ''; + @Builder + PassBtn(text: Resource, isFullScreen: boolean) { + if(this.Vue == false){ + Button({stateEffect:this.Vue}) { + Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey).opacity(0.4) + .onClick(()=>{ + + }) + } + else{ + Button({stateEffect:this.Vue}) { + Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(()=>{ + router.back({ + url:this.Url, + params: {result : 'Pass', title : this.name, + } + }) + this.getScreen(isFullScreen); + prompt.showToast({ + message: '通过', duration: 1000 + }); + }) + } + } + @Builder + FailBtn(text: Resource, isFullScreen: boolean) { + Button(){ + Image($r('app.media.ic_public_fail')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(()=>{ + router.back({ + url:this.Url, + params: {result : 'Fail',title : this.name, + } + }) + this.getScreen(isFullScreen); + prompt.showToast({ + message: '失败', duration: 1000 + }); + }) + } + build() { + Column() { + Flex({ + justifyContent: FlexAlign.SpaceEvenly, alignItems: ItemAlign.Center + }){ + this.PassBtn($r('app.string.btn_fullscreen'), true); + Button(){ + Image($r('app.media.ic_public_help')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(() =>{ + AlertDialog.show( + { + title:'操作提示', + message: this.StepTips, + confirm:{ + value:'OK', + action:()=>{ + } + } + } + ) + }) + this.FailBtn($r('app.string.btn_fullscreen'), true); + }.height('98%').width('100%').backgroundColor(Color.Black) + }.height('98%').width('100%') + } + + async savePicture(data: image.PixelMap, context: any) { + Logger.info(TAG, `savePicture`); + let packOpts: image.PackingOption = { + format: "image/jpeg", quality: 100 + }; + let info = { + prefix: 'IMG_', suffix: '.jpg', directory: mediaLibrary.DirectoryType.DIR_IMAGE + }; + let name = this.name; + let displayName = `${info.prefix}${name}${info.suffix}`; + let dirPath = path + '/' + displayName; + let imagePackerApi = image.createImagePacker(); + let arrayBuffer = await imagePackerApi.packing(data, packOpts); + let fd = fileio.openSync(dirPath,0o102,0o666); + imagePackerApi.release(); + try { + await fileio.write(fd, arrayBuffer); + } catch (err) { + Logger.error(`write failed, code is ${err.code}, message is ${err.message}`); + } + await fileio.close(fd); + Logger.info(TAG, `write done`); + } + getScreen = (isFullScreen: boolean) => { + let screenshotOptions: screenshot.ScreenshotOptions = { + screenRect: { left: 0, top: 0, width: 400, height: 400 }, + imageSize: { width: 400, height: 400 }, + rotation: 0, + displayId: 0 + }; + if (isFullScreen) { + screenshotOptions = { + rotation: 0 + } + } + try { + screenshot.save(screenshotOptions, (err, data: image.PixelMap) => { + if (err) { + Logger.info(TAG, `Failed to save the screenshot. Error:${JSON.stringify(err)}`); + } + Logger.info(TAG, 'save callback'); + this.savePicture(data, getContext(this) as any); + }) + } catch (err) { + Logger.error(`save failed, code is ${err.code}, message is ${err.message}`); + } + } +} diff --git a/validator/acts_validator/src/main/ets/pages/common/CameraVideoContainer.ets b/validator/acts_validator/src/main/ets/pages/common/CameraVideoContainer.ets new file mode 100644 index 0000000000000000000000000000000000000000..46c0812e0128dddab83a8b1609b40691a2aa40ee --- /dev/null +++ b/validator/acts_validator/src/main/ets/pages/common/CameraVideoContainer.ets @@ -0,0 +1,153 @@ +/* + * 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 fileio from '@ohos.fileio'; +import prompt from '@ohos.prompt'; +import router from '@ohos.router'; +// @ts-ignore +import screenshot from '@ohos.screenshot'; +import image from '@ohos.multimedia.image'; +import Logger from '../model/Logger'; +import mediaLibrary from '@ohos.multimedia.mediaLibrary'; + +let path = globalThis.dir; +const TAG = '[Screenshot]'; +@Component +export struct CustomContainer { + @Link FillColor: string; + @Link name: string; + @Link Vue : boolean; + Url : string = ''; + title : string = ''; + StepTips: string = ''; + @Builder + PassBtn(text: Resource, isFullScreen: boolean) { + if(this.Vue == false){ + Button({stateEffect:this.Vue}) { + Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey).opacity(0.4) + .onClick(()=>{ + + }) + } + else{ + Button({stateEffect:this.Vue}) { + Image($r('app.media.ic_public_pass')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(()=>{ + router.back({ + url:this.Url, + params: {result : 'Pass', title : this.name, + } + }) + this.getScreen(isFullScreen); + prompt.showToast({ + message: '通过', duration: 1000 + }); + }) + } + } + @Builder + FailBtn(text: Resource, isFullScreen: boolean) { + Button(){ + Image($r('app.media.ic_public_fail')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(()=>{ + router.back({ + url:this.Url, + params: {result : 'Fail',title : this.name, + } + }) + this.getScreen(isFullScreen); + prompt.showToast({ + message: '失败', duration: 1000 + }); + }) + } + build() { + Column() { + Flex({ + justifyContent: FlexAlign.SpaceEvenly, alignItems: ItemAlign.Center + }){ + this.PassBtn($r('app.string.btn_fullscreen'), true); + Button(){ + Image($r('app.media.ic_public_help')).width('20vp').height('20vp') + }.width('30%').height('30vp').backgroundColor(Color.Grey) + .onClick(() =>{ + AlertDialog.show( + { + title:'操作提示', + message: this.StepTips, + confirm:{ + value:'OK', + action:()=>{ + } + } + } + ) + }) + this.FailBtn($r('app.string.btn_fullscreen'), true); + }.height('98%').width('100%').backgroundColor(Color.Black) + }.height('98%').width('100%') + } + + async savePicture(data: image.PixelMap, context: any) { + Logger.info(TAG, `savePicture`); + let packOpts: image.PackingOption = { + format: "image/jpeg", quality: 100 + }; + let info = { + prefix: 'IMG_', suffix: '.jpg', directory: mediaLibrary.DirectoryType.DIR_IMAGE + }; + let name = this.name; + let displayName = `${info.prefix}${name}${info.suffix}`; + let dirPath = path + '/' + displayName; + let imagePackerApi = image.createImagePacker(); + let arrayBuffer = await imagePackerApi.packing(data, packOpts); + let fd = fileio.openSync(dirPath,0o102,0o666); + imagePackerApi.release(); + try { + await fileio.write(fd, arrayBuffer); + } catch (err) { + Logger.error(`write failed, code is ${err.code}, message is ${err.message}`); + } + await fileio.close(fd); + Logger.info(TAG, `write done`); + } + getScreen = (isFullScreen: boolean) => { + let screenshotOptions: screenshot.ScreenshotOptions = { + screenRect: { left: 0, top: 0, width: 400, height: 400 }, + imageSize: { width: 400, height: 400 }, + rotation: 0, + displayId: 0 + }; + if (isFullScreen) { + screenshotOptions = { + rotation: 0 + } + } + try { + screenshot.save(screenshotOptions, (err, data: image.PixelMap) => { + if (err) { + Logger.info(TAG, `Failed to save the screenshot. Error:${JSON.stringify(err)}`); + } + Logger.info(TAG, 'save callback'); + this.savePicture(data, getContext(this) as any); + }) + } catch (err) { + Logger.error(`save failed, code is ${err.code}, message is ${err.message}`); + } + } +} diff --git a/validator/acts_validator/src/main/ets/pages/model/CameraService.ts b/validator/acts_validator/src/main/ets/pages/model/CameraService.ts deleted file mode 100644 index a7326f767ae27d1070c7bc5346f8d5ef6097a66b..0000000000000000000000000000000000000000 --- a/validator/acts_validator/src/main/ets/pages/model/CameraService.ts +++ /dev/null @@ -1,326 +0,0 @@ -/* - * 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 camera from '@ohos.multimedia.camera' -import deviceInfo from '@ohos.deviceInfo' -import fileio from '@ohos.fileio' -import image from '@ohos.multimedia.image' -import media from '@ohos.multimedia.media' -import mediaLibrary from '@ohos.multimedia.mediaLibrary' -import Logger from '../model/Logger' -import MediaUtils from '../model/MediaUtils' - -const CameraMode = { - MODE_PHOTO: 0, // 拍照模式 - MODE_VIDEO: 1 // 录像模式 -} - -//const CameraSize = { -// WIDTH: 1280, -// HEIGHT: 960 -//} -const CameraSize = { - WIDTH: 4096, - HEIGHT: 3072 -} - -class CameraService { - private tag: string = 'qlw CameraService' - private static instance: CameraService = new CameraService() - private mediaUtil = MediaUtils.getInstance() - private cameraManager: camera.CameraManager = undefined - private cameras: Array = undefined - private cameraOutputCapability: camera.CameraOutputCapability = undefined - private cameraId: string = '' - private cameraInput: camera.CameraInput = undefined - private previewOutput: camera.PreviewOutput = undefined - private photoOutPut: camera.PhotoOutput = undefined - private captureSession: camera.CaptureSession = undefined - private mReceiver: image.ImageReceiver = undefined - private photoUri: string = '' - private fileAsset: mediaLibrary.FileAsset = undefined - private fd: number = -1 - private curMode = CameraMode.MODE_PHOTO - private videoRecorder: media.VideoRecorder = undefined - private videoOutput: camera.VideoOutput = undefined - private handleTakePicture: (photoUri: string) => void = undefined - private mirrorValue: boolean = false - private videoConfig: any = { - audioSourceType: 1, - videoSourceType: 0, - profile: { - audioBitrate: 48000, - audioChannels: 2, - audioCodec: 'audio/mp4v-es', - audioSampleRate: 48000, - durationTime: 1000, - fileFormat: 'mp4', - videoBitrate: 48000, - videoCodec: 'video/mp4v-es', -// videoFrameWidth: globalThis.videoSize.width, -// videoFrameHeight: globalThis.videoSize.height, - videoFrameWidth: 176, - videoFrameHeight: 144, - videoFrameRate: 30 - }, - url: '', - orientationHint: 0, - location: { latitude: 30, longitude: 130 }, - maxSize: 10000, - maxDuration: 10000 - } - - constructor() { - this.mReceiver = image.createImageReceiver(CameraSize.WIDTH, CameraSize.HEIGHT, image.ImageFormat.JPEG, 8) - Logger.info(this.tag, 'createImageReceiver') - this.mReceiver.on('imageArrival', () => { - Logger.info(this.tag, 'imageArrival') - this.mReceiver.readNextImage((err, image) => { - Logger.info(this.tag, 'readNextImage') - if (err || image === undefined) { - Logger.error(this.tag, 'failed to get valid image') - return - } - image.getComponent(4, (errMsg, img) => { - Logger.info(this.tag, 'getComponent') - if (errMsg || img === undefined) { - Logger.info(this.tag, 'failed to get valid buffer') - return - } - let buffer - if (img.byteBuffer) { - buffer = img.byteBuffer - } else { - Logger.error(this.tag, 'img.byteBuffer is undefined') - } - this.savePicture(buffer, image) - }) - }) - }) - } - - async savePicture(buffer: ArrayBuffer, img: image.Image) { - Logger.info(this.tag, 'savePicture') - this.fileAsset = await this.mediaUtil.createAndGetUri(mediaLibrary.MediaType.IMAGE) - this.photoUri = this.fileAsset.uri - Logger.info(this.tag, `this.photoUri = ${this.photoUri}`) - this.fd = await this.mediaUtil.getFdPath(this.fileAsset) - Logger.info(this.tag, `this.fd = ${this.fd}`) - await fileio.write(this.fd, buffer) - await this.fileAsset.close(this.fd) - await img.release() - Logger.info(this.tag, 'save image done') - if (this.handleTakePicture) { - this.handleTakePicture(this.photoUri) - } - } - - async initCamera(surfaceId: number, cameraDeviceIndex: number) { - try{ - Logger.info(this.tag, 'initCamera') - if (this.curMode === CameraMode.MODE_VIDEO) { - await this.releaseCamera() - } - if (this.curMode === CameraMode.MODE_PHOTO) { - await this.releasePhotoCamera() - } - Logger.info(this.tag, `deviceInfo.deviceType = ${deviceInfo.deviceType}`) - if (deviceInfo.deviceType === 'default') { - this.videoConfig.videoSourceType = 1 - } else { - this.videoConfig.videoSourceType = 0 - } - this.cameraManager = await camera.getCameraManager(globalThis.abilityContext) - Logger.info(this.tag, 'getCameraManager') - this.cameras = await this.cameraManager.getSupportedCameras() - Logger.info(this.tag, `get cameras ${this.cameras.length}`) - if (this.cameras.length === 0) { - Logger.info(this.tag, 'cannot get cameras') - return - } - this.cameraInput = await this.cameraManager.createCameraInput(this.cameras[cameraDeviceIndex]) - await this.cameraInput.open((err) => { - if(err){ - Logger.info(this.tag, `cameraInput open Failed : ${err}`) - return - } - Logger.info(this.tag, `cameraInput open success`) - }) - Logger.info(this.tag, 'createCameraInput') - this.cameraOutputCapability = await this.cameraManager.getSupportedOutputCapability(this.cameras[cameraDeviceIndex]) - Logger.info(this.tag, 'cameraOutputCapability: ' + JSON.stringify(this.cameraOutputCapability)) - Logger.info(this.tag, 'cameraOutputCapability previewProfiles: ' + JSON.stringify(this.cameraOutputCapability.previewProfiles)) - Logger.info(this.tag, 'cameraOutputCapability photoProfiles: ' + JSON.stringify(this.cameraOutputCapability.photoProfiles)) - Logger.info(this.tag, 'cameraOutputCapability videoProfiles: ' + JSON.stringify(this.cameraOutputCapability.videoProfiles)) - - this.previewOutput = await this.cameraManager.createPreviewOutput(this.cameraOutputCapability.previewProfiles[0], surfaceId.toString()) - Logger.info(this.tag, 'createPreviewOutput') - let mSurfaceId = await this.mReceiver.getReceivingSurfaceId() - this.photoOutPut = await this.cameraManager.createPhotoOutput(this.cameraOutputCapability.photoProfiles[0], (mSurfaceId)) - Logger.info(this.tag, 'createPhotoOutput') - this.captureSession = await this.cameraManager.createCaptureSession() - Logger.info(this.tag, 'createCaptureSession') - await this.captureSession.beginConfig() - Logger.info(this.tag, 'beginConfig') - await this.captureSession.addInput(this.cameraInput) - await this.captureSession.addOutput(this.previewOutput) - await this.captureSession.addOutput(this.photoOutPut) - await this.captureSession.commitConfig() - await this.captureSession.start() - Logger.info(this.tag, 'captureSession start') - }catch(err){ - Logger.info(this.tag, 'initCamera err: ' + err) - } - - } - - setTakePictureCallback(callback) { - this.handleTakePicture = callback - } - - async takePicture(rotationValue, qualityLevel) { - Logger.info(this.tag, 'takePicture') - if (this.curMode === CameraMode.MODE_VIDEO) { - this.curMode = CameraMode.MODE_PHOTO - } -// if(this.photoOutPut.isMirrorSupported()){ -// this.mirrorValue = true -// } - let photoSettings = { - rotation: rotationValue, - quality: qualityLevel, - location: { // 位置信息,经纬度 - latitude: 0, - longitude: 0, - altitude: 1000 - }, - mirror: this.mirrorValue - } - Logger.info(this.tag, JSON.stringify(photoSettings)) - try{ - await this.photoOutPut.capture(photoSettings) - }catch(err){ - Logger.info(this.tag, `takePicture err ${err.message}`) - } - - Logger.info(this.tag, 'takePicture done') - } - - async startVideo() { - try{ - Logger.info(this.tag, 'startVideo begin') - await this.captureSession.stop() - - await this.captureSession.beginConfig() - Logger.info(this.tag, 'beginConfig') - if (this.curMode === CameraMode.MODE_PHOTO) { - this.curMode = CameraMode.MODE_VIDEO - if (this.photoOutPut) { - await this.captureSession.removeOutput(this.photoOutPut) - } - } else { - if (this.videoOutput) { - await this.captureSession.removeOutput(this.videoOutput) - } - } - }catch(err){ - Logger.info(this.tag, 'startVideo err1: ' + err) - } - - this.fileAsset = await this.mediaUtil.createAndGetUri(mediaLibrary.MediaType.VIDEO) - this.fd = await this.mediaUtil.getFdPath(this.fileAsset) - this.videoRecorder = await media.createVideoRecorder() - this.videoConfig.url = `fd://${this.fd}` - await this.videoRecorder.prepare(this.videoConfig) - let videoId = await this.videoRecorder.getInputSurface() - Logger.info(this.tag, `cameraOutputCapability.videoProfiles ${this.cameraOutputCapability.videoProfiles.length}`) -// let index = 0 -// this.videoOutput = await this.cameraManager.createVideoOutput(this.cameraOutputCapability.videoProfiles[index], videoId) - - // @ts-ignore - let videoProfilesObj: camera.VideoProfile = { - "format": 1003, - "size":{ - "width": 176, - "height": 144 - }, - "frameRateRange":{ - "min": -1, - "max": 0 - } - } - try{ - this.videoOutput = await this.cameraManager.createVideoOutput(videoProfilesObj, videoId) - await this.captureSession.addOutput(this.videoOutput) - await this.captureSession.commitConfig() - Logger.info(this.tag, 'captureSession commitConfig') - await this.captureSession.start() - Logger.info(this.tag, 'captureSession start') - await this.videoOutput.start() - Logger.info(this.tag, 'videoOutput start') - await this.videoRecorder.start() - Logger.info(this.tag, 'videoRecorder start') - }catch(err){ - Logger.info(this.tag, 'startVideo err2: ' + err) - } - } - - async stopVideo() { - Logger.info(this.tag, 'stopVideo called') - await this.videoRecorder.stop() - await this.videoRecorder.release() - await this.videoOutput.stop() - await this.fileAsset.close(this.fd) - } - - async releaseCamera() { - Logger.info(this.tag, 'releaseCamera') - if (this.cameraInput) { - // @ts-ignore - await this.cameraInput.release() - } - if (this.previewOutput) { - await this.previewOutput.release() - } - if (this.photoOutPut) { - await this.photoOutPut.release() - } - if (this.videoOutput) { - await this.videoOutput.release() - } - if (this.captureSession) { - await this.captureSession.release() - } - } - - async releasePhotoCamera() { - Logger.info(this.tag, 'releaseCamera') - if (this.cameraInput) { - // @ts-ignore - await this.cameraInput.release() - } - if (this.previewOutput) { - await this.previewOutput.release() - } - if (this.photoOutPut) { - await this.photoOutPut.release() - } - if (this.captureSession) { - await this.captureSession.release() - } - } -} - -export default new CameraService() \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/model/DateTimeUtil.ts b/validator/acts_validator/src/main/ets/pages/model/DateTimeUtil.ts deleted file mode 100644 index 31378b8f0d056b714695ec630f0e115cc002a010..0000000000000000000000000000000000000000 --- a/validator/acts_validator/src/main/ets/pages/model/DateTimeUtil.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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. - */ - -/** - * @file 日期工具 - */ -export default class DateTimeUtil { - - /** - * 时分秒 - */ - getTime() { - const DATETIME = new Date() - return this.concatTime(DATETIME.getHours(), DATETIME.getMinutes(), DATETIME.getSeconds()) - } - getHour() { - const DATETIME = new Date() - return DATETIME.getHours() - } - getMinute() { - const DATETIME = new Date() - return DATETIME.getMinutes() - } - getSecond() { - const DATETIME = new Date() - return DATETIME.getSeconds() - } - - /** - * 年月日 - */ - getDate() { - const DATETIME = new Date() - return this.concatDate(DATETIME.getFullYear(), DATETIME.getMonth() + 1, DATETIME.getDate()) - } - getFullYear() { - const DATETIME = new Date() - return DATETIME.getFullYear() - } - getMonth() { - const DATETIME = new Date() - return DATETIME.getMonth() + 1 - } - getDay() { - const DATETIME = new Date() - return DATETIME.getDate() - } - - /** - * 日期不足两位补充0 - * @param value-数据值 - */ - fill(value: number) { - return (value > 9 ? '' : '0') + value - } - - /** - * 年月日格式修饰 - * @param year - * @param month - * @param date - */ - concatDate(year: number, month: number, date: number) { - return `${year}${this.fill(month)}${this.fill(date)}` - } - - /** - * 时分秒格式修饰 - * @param hours - * @param minutes - * @param seconds - */ - concatTime(hours: number, minutes: number, seconds: number) { - return `${this.fill(hours)}${this.fill(minutes)}${this.fill(seconds)}` - } -} \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/model/Logger.ts b/validator/acts_validator/src/main/ets/pages/model/Logger.ts deleted file mode 100644 index b69da312cced75f5474ed1e8239f7ef9fd6f76ec..0000000000000000000000000000000000000000 --- a/validator/acts_validator/src/main/ets/pages/model/Logger.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 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: any[]) { - hilog.debug(this.domain, this.prefix, this.format, args); - } - - info(...args: any[]) { - hilog.info(this.domain, this.prefix, this.format, args); - } - - warn(...args: any[]) { - hilog.warn(this.domain, this.prefix, this.format, args); - } - - error(...args: any[]) { - hilog.error(this.domain, this.prefix, this.format, args); - } -} - -export default new Logger('[Screenshot]'); \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/model/MediaUtils.ts b/validator/acts_validator/src/main/ets/pages/model/MediaUtils.ts deleted file mode 100644 index d6e6bc8945b949b6692735508b7b09deb41b474d..0000000000000000000000000000000000000000 --- a/validator/acts_validator/src/main/ets/pages/model/MediaUtils.ts +++ /dev/null @@ -1,180 +0,0 @@ -/* - * 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 mediaLibrary from '@ohos.multimedia.mediaLibrary' -import DateTimeUtil from '../model/DateTimeUtil' -import Logger from './Logger' - -export default class MediaUtils { - private tag: string = 'qlw MediaUtils' - private mediaTest: mediaLibrary.MediaLibrary = mediaLibrary.getMediaLibrary(globalThis.abilityContext) - private static instance: MediaUtils = new MediaUtils() - - public static getInstance() { - if (this.instance === undefined) { - this.instance = new MediaUtils() - } - return this.instance - } - - async createAndGetUri(mediaType: number) { - let info = this.getInfoFromType(mediaType) - let dateTimeUtil = new DateTimeUtil() - let name = `${dateTimeUtil.getDate()}_${dateTimeUtil.getTime()}` - let displayName = `${info.prefix}${name}${info.suffix}` - Logger.info(this.tag, `displayName = ${displayName},mediaType = ${mediaType}`) - let publicPath = await this.mediaTest.getPublicDirectory(info.directory) - Logger.info(this.tag, `publicPath = ${publicPath}`) - return await this.mediaTest.createAsset(mediaType, displayName, publicPath) - } - - async queryFile(dataUri: any) { - let fileKeyObj = mediaLibrary.FileKey - if (dataUri !== undefined) { - let args = dataUri.id.toString() - let fetchOp = { - selections: `${fileKeyObj.ID}=?`, - selectionArgs: [args], - } - const fetchFileResult = await this.mediaTest.getFileAssets(fetchOp) - Logger.info(this.tag, `fetchFileResult.getCount() = ${fetchFileResult.getCount()}`) - const fileAsset = await fetchFileResult.getAllObject() - return fileAsset[0] - } - } - - async getFdPath(fileAsset: any) { - let fd = await fileAsset.open('Rw') - Logger.info(this.tag, `fd = ${fd}`) - return fd - } - - async createFile(mediaType: number) { - let dataUri = await this.createAndGetUri(mediaType) - if (dataUri) { - let fileAsset = await this.queryFile(dataUri) - if (fileAsset) { - let fd = await this.getFdPath(fileAsset) - return fd - } - } - } - - async getFileAssetsFromType(mediaType: number) { - Logger.info(this.tag, `getFileAssetsFromType,mediaType = ${mediaType}`) - let fileKeyObj = mediaLibrary.FileKey - let fetchOp = { - selections: `${fileKeyObj.MEDIA_TYPE}=?`, - selectionArgs: [`${mediaType}`], - } - const fetchFileResult = await this.mediaTest.getFileAssets(fetchOp) - Logger.info(this.tag, `getFileAssetsFromType,fetchFileResult.count = ${fetchFileResult.getCount()}`) - let fileAssets = [] - if (fetchFileResult.getCount() > 0) { - fileAssets = await fetchFileResult.getAllObject() - } - return fileAssets - } - - async getAlbums() { - Logger.info(this.tag, 'getAlbums begin') - let albums = [] - const [ files, images, videos, audios ] = await Promise.all([ - this.getFileAssetsFromType(mediaLibrary.MediaType.FILE), - this.getFileAssetsFromType(mediaLibrary.MediaType.IMAGE), - this.getFileAssetsFromType(mediaLibrary.MediaType.VIDEO), - this.getFileAssetsFromType(mediaLibrary.MediaType.AUDIO) - ]) - albums.push({ - albumName: 'Documents', count: files.length, mediaType: mediaLibrary.MediaType.FILE - }) - albums.push({ - albumName: 'Pictures', count: images.length, mediaType: mediaLibrary.MediaType.IMAGE - }) - albums.push({ - albumName: 'Videos', count: videos.length, mediaType: mediaLibrary.MediaType.VIDEO - }) - albums.push({ - albumName: 'Audios', count: audios.length, mediaType: mediaLibrary.MediaType.AUDIO - }) - return albums - } - - deleteFile(media: any) { - let uri = media.uri - Logger.info(this.tag, `deleteFile,uri = ${uri}`) - return this.mediaTest.deleteAsset(uri) - } - - onDateChange(callback: () => void) { - this.mediaTest.on('albumChange', () => { - Logger.info(this.tag, 'albumChange called') - callback() - }) - this.mediaTest.on('imageChange', () => { - Logger.info(this.tag, 'imageChange called') - callback() - }) - this.mediaTest.on('audioChange', () => { - Logger.info(this.tag, 'audioChange called') - callback() - }) - this.mediaTest.on('videoChange', () => { - Logger.info(this.tag, 'videoChange called') - callback() - }) - this.mediaTest.on('fileChange', () => { - Logger.info(this.tag, 'fileChange called') - callback() - }) - } - - offDateChange() { - this.mediaTest.off('albumChange') - this.mediaTest.off('imageChange') - this.mediaTest.off('audioChange') - this.mediaTest.off('videoChange') - this.mediaTest.off('fileChange') - } - - getInfoFromType(mediaType: number) { - let result = { - prefix: '', suffix: '', directory: 0 - } - switch (mediaType) { - case mediaLibrary.MediaType.FILE: - result.prefix = 'FILE_' - result.suffix = '.txt' - result.directory = mediaLibrary.DirectoryType.DIR_DOCUMENTS - break - case mediaLibrary.MediaType.IMAGE: - result.prefix = 'IMG_' - result.suffix = '.jpg' - result.directory = mediaLibrary.DirectoryType.DIR_IMAGE - break - case mediaLibrary.MediaType.VIDEO: - result.prefix = 'VID_' - result.suffix = '.mp4' - result.directory = mediaLibrary.DirectoryType.DIR_VIDEO - break - case mediaLibrary.MediaType.AUDIO: - result.prefix = 'AUD_' - result.suffix = '.wav' - result.directory = mediaLibrary.DirectoryType.DIR_AUDIO - break - } - return result - } -} \ No newline at end of file diff --git a/validator/acts_validator/src/main/ets/pages/model/RecordModel.ts b/validator/acts_validator/src/main/ets/pages/model/RecordModel.ts deleted file mode 100644 index e5316464bd806e0c58daae2c7752648400b39dfd..0000000000000000000000000000000000000000 --- a/validator/acts_validator/src/main/ets/pages/model/RecordModel.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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 media from '@ohos.multimedia.media' -import Logger from '../model/Logger' - -let audioConfig = { - audioSourceType: 1, - audioEncoder: 3, - audioEncodeBitRate: 22050, - audioSampleRate: 22050, - numberOfChannels: 2, - format: 6, - uri: '' -} - -export default class RecordModel { - private tag: string = 'qlw RecordModel' - private audioRecorder: media.AudioRecorder = undefined - - initAudioRecorder(handleStateChange: () => void) { - this.release(); - this.audioRecorder = media.createAudioRecorder() - Logger.info(this.tag, 'create audioRecorder success') - this.audioRecorder.on('prepare', () => { - Logger.info(this.tag, 'setCallback prepare case callback is called') - this.audioRecorder.start() - }) - this.audioRecorder.on('start', () => { - Logger.info(this.tag, 'setCallback start case callback is called') - handleStateChange() - }) - this.audioRecorder.on('stop', () => { - Logger.info(this.tag, 'audioRecorder stop called') - this.audioRecorder.release() - }) - this.audioRecorder.on('pause', () => { - Logger.info(this.tag, 'audioRecorder pause finish') - handleStateChange() - }) - this.audioRecorder.on('resume', () => { - Logger.info(this.tag, 'audioRecorder resume finish') - handleStateChange() - }) - } - - release() { - if (typeof (this.audioRecorder) !== `undefined`) { - Logger.info(this.tag, 'audioRecorder release') - this.audioRecorder.release() - this.audioRecorder = undefined - } - } - - startRecorder(pathName: string) { - Logger.info(this.tag, `startRecorder, pathName = ${pathName}`) - if (typeof (this.audioRecorder) !== 'undefined') { - Logger.info(this.tag, 'start prepare') - audioConfig.uri = pathName - this.audioRecorder.prepare(audioConfig) - } else { - Logger.error(this.tag, 'case failed, audioRecorder is null') - } - } - - pause() { - Logger.info(this.tag, 'audioRecorder pause called') - if (typeof (this.audioRecorder) !== `undefined`) { - this.audioRecorder.pause() - } - } - - resume() { - Logger.info(this.tag, 'audioRecorder resume called') - if (typeof (this.audioRecorder) !== `undefined`) { - this.audioRecorder.resume() - } - } - - finish() { - if (typeof (this.audioRecorder) !== `undefined`) { - this.audioRecorder.stop() - } - } -} \ No newline at end of file diff --git a/validator/acts_validator/src/main/resources/base/media/icon_pause.svg b/validator/acts_validator/src/main/resources/base/media/icon_pause.svg new file mode 100644 index 0000000000000000000000000000000000000000..04683d1d12fea8e28836d559fe3ceed9f7b2fd2b --- /dev/null +++ b/validator/acts_validator/src/main/resources/base/media/icon_pause.svg @@ -0,0 +1,13 @@ + + + icon_pause + + + + + + + + + + \ No newline at end of file diff --git a/validator/acts_validator/src/main/resources/base/media/icon_play.svg b/validator/acts_validator/src/main/resources/base/media/icon_play.svg new file mode 100644 index 0000000000000000000000000000000000000000..f5464c9de9ebff364e2d2006d9808b4100705512 --- /dev/null +++ b/validator/acts_validator/src/main/resources/base/media/icon_play.svg @@ -0,0 +1,13 @@ + + + icon_play + + + + + + + + + + \ No newline at end of file diff --git a/validator/acts_validator/src/main/resources/base/profile/main_pages.json b/validator/acts_validator/src/main/resources/base/profile/main_pages.json index dc2ee2fc161441ac6643cd6ab6a7abacce50b35c..c235d7f8d9d950c9c820547a5552024a5f74774b 100644 --- a/validator/acts_validator/src/main/resources/base/profile/main_pages.json +++ b/validator/acts_validator/src/main/resources/base/profile/main_pages.json @@ -26,12 +26,21 @@ "pages/ArkUI/CanvasLineDashOffset", "pages/ArkUI/CanvasShadowOffsetY", "pages/Camera/Camera_index", - "pages/Camera/CameraFormat", + "pages/Camera/CameraPreviewFormat", + "pages/Camera/CameraPhotoFormat", + "pages/Camera/CameraOrientation", + "pages/Camera/CameraSerialPhoto", "pages/Camera/CameraVideo", + "pages/Camera/CameraFlash", "pages/Audio/Audio_index", - "pages/Audio/ScrollListTest", + "pages/Audio/AudioInputRoutingWiredHeadset", + "pages/Audio/AudioInputRoutingTypeC", + "pages/Audio/AudioOutputRoutingWiredHeadset", + "pages/Audio/AudioOutputRoutingTypeC", + "pages/Audio/AudioOutputRoutingBT", "pages/Player/Player_index", - "pages/Player/ScrollListTest", + "pages/Player/PlayAudio", + "pages/Player/PlayVideo", "pages/Experience/Experience_index", "pages/Experience/PhotoFps", "pages/Experience/DeskFps", diff --git a/validator/acts_validator/src/main/resources/rawfile/H264_AAC.mkv b/validator/acts_validator/src/main/resources/rawfile/H264_AAC.mkv new file mode 100644 index 0000000000000000000000000000000000000000..75c632a71614335e48fedc5bfec1d0b24e187be5 Binary files /dev/null and b/validator/acts_validator/src/main/resources/rawfile/H264_AAC.mkv differ diff --git a/validator/acts_validator/src/main/resources/rawfile/StarWars10s-1C-44100-2SW.wav b/validator/acts_validator/src/main/resources/rawfile/StarWars10s-1C-44100-2SW.wav new file mode 100644 index 0000000000000000000000000000000000000000..fb7e0f649f81179ef297a85437d97639bd7c2dfd Binary files /dev/null and b/validator/acts_validator/src/main/resources/rawfile/StarWars10s-1C-44100-2SW.wav differ diff --git a/validator/acts_validator/src/main/resources/rawfile/test_44100_2.wav b/validator/acts_validator/src/main/resources/rawfile/test_44100_2.wav new file mode 100644 index 0000000000000000000000000000000000000000..a04c1cdbc7ea143da327d8d0829b165c8bef574b Binary files /dev/null and b/validator/acts_validator/src/main/resources/rawfile/test_44100_2.wav differ