Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
Xts Acts
提交
eaf9538d
X
Xts Acts
项目概览
OpenHarmony
/
Xts Acts
1 年多 前同步成功
通知
9
Star
22
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
X
Xts Acts
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
eaf9538d
编写于
3月 17, 2023
作者:
Q
qinliwen
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
<新增camera&audio&player Validator用例>
Signed-off-by:
N
qinliwen
<
qinliwen3@huawei.com
>
上级
2c753396
变更
35
隐藏空白更改
内联
并排
Showing
35 changed file
with
3251 addition
and
1085 deletion
+3251
-1085
validator/acts_validator/AppScope/app.json
validator/acts_validator/AppScope/app.json
+1
-1
validator/acts_validator/src/main/ets/pages/Audio/AudioInputRoutingTypeC.ets
...dator/src/main/ets/pages/Audio/AudioInputRoutingTypeC.ets
+192
-0
validator/acts_validator/src/main/ets/pages/Audio/AudioInputRoutingWiredHeadset.ets
...rc/main/ets/pages/Audio/AudioInputRoutingWiredHeadset.ets
+192
-0
validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingBT.ets
...lidator/src/main/ets/pages/Audio/AudioOutputRoutingBT.ets
+172
-0
validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingTypeC.ets
...ator/src/main/ets/pages/Audio/AudioOutputRoutingTypeC.ets
+172
-0
validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingWiredHeadset.ets
...c/main/ets/pages/Audio/AudioOutputRoutingWiredHeadset.ets
+171
-0
validator/acts_validator/src/main/ets/pages/Audio/Audio_index.ets
...r/acts_validator/src/main/ets/pages/Audio/Audio_index.ets
+5
-1
validator/acts_validator/src/main/ets/pages/Camera/CameraFlash.ets
.../acts_validator/src/main/ets/pages/Camera/CameraFlash.ets
+132
-0
validator/acts_validator/src/main/ets/pages/Camera/CameraFormat.ets
...acts_validator/src/main/ets/pages/Camera/CameraFormat.ets
+0
-118
validator/acts_validator/src/main/ets/pages/Camera/CameraOrientation.ets
...validator/src/main/ets/pages/Camera/CameraOrientation.ets
+174
-0
validator/acts_validator/src/main/ets/pages/Camera/CameraPhotoFormat.ets
...validator/src/main/ets/pages/Camera/CameraPhotoFormat.ets
+254
-0
validator/acts_validator/src/main/ets/pages/Camera/CameraPreviewFormat.ets
...lidator/src/main/ets/pages/Camera/CameraPreviewFormat.ets
+227
-0
validator/acts_validator/src/main/ets/pages/Camera/CameraSerialPhoto.ets
...validator/src/main/ets/pages/Camera/CameraSerialPhoto.ets
+189
-0
validator/acts_validator/src/main/ets/pages/Camera/CameraVideo.ets
.../acts_validator/src/main/ets/pages/Camera/CameraVideo.ets
+233
-58
validator/acts_validator/src/main/ets/pages/Camera/Camera_index.ets
...acts_validator/src/main/ets/pages/Camera/Camera_index.ets
+6
-3
validator/acts_validator/src/main/ets/pages/Player/PlayAudio.ets
...or/acts_validator/src/main/ets/pages/Player/PlayAudio.ets
+79
-0
validator/acts_validator/src/main/ets/pages/Player/PlayVideo.ets
...or/acts_validator/src/main/ets/pages/Player/PlayVideo.ets
+80
-0
validator/acts_validator/src/main/ets/pages/Player/Player_index.ets
...acts_validator/src/main/ets/pages/Player/Player_index.ets
+2
-1
validator/acts_validator/src/main/ets/pages/common/AudioContainer.ets
...ts_validator/src/main/ets/pages/common/AudioContainer.ets
+148
-0
validator/acts_validator/src/main/ets/pages/common/CameraFlashContainer.ets
...idator/src/main/ets/pages/common/CameraFlashContainer.ets
+164
-0
validator/acts_validator/src/main/ets/pages/common/CameraOrientationContainer.ets
.../src/main/ets/pages/common/CameraOrientationContainer.ets
+161
-0
validator/acts_validator/src/main/ets/pages/common/CameraPhotoContainer.ets
...idator/src/main/ets/pages/common/CameraPhotoContainer.ets
+153
-165
validator/acts_validator/src/main/ets/pages/common/CameraPreviewFormatContainer.ets
...rc/main/ets/pages/common/CameraPreviewFormatContainer.ets
+153
-0
validator/acts_validator/src/main/ets/pages/common/CameraVideoContainer.ets
...idator/src/main/ets/pages/common/CameraVideoContainer.ets
+153
-0
validator/acts_validator/src/main/ets/pages/model/CameraService.ts
.../acts_validator/src/main/ets/pages/model/CameraService.ts
+0
-326
validator/acts_validator/src/main/ets/pages/model/DateTimeUtil.ts
...r/acts_validator/src/main/ets/pages/model/DateTimeUtil.ts
+0
-88
validator/acts_validator/src/main/ets/pages/model/Logger.ts
validator/acts_validator/src/main/ets/pages/model/Logger.ts
+0
-44
validator/acts_validator/src/main/ets/pages/model/MediaUtils.ts
...tor/acts_validator/src/main/ets/pages/model/MediaUtils.ts
+0
-180
validator/acts_validator/src/main/ets/pages/model/RecordModel.ts
...or/acts_validator/src/main/ets/pages/model/RecordModel.ts
+0
-97
validator/acts_validator/src/main/resources/base/media/icon_pause.svg
...ts_validator/src/main/resources/base/media/icon_pause.svg
+13
-0
validator/acts_validator/src/main/resources/base/media/icon_play.svg
...cts_validator/src/main/resources/base/media/icon_play.svg
+13
-0
validator/acts_validator/src/main/resources/base/profile/main_pages.json
...validator/src/main/resources/base/profile/main_pages.json
+12
-3
validator/acts_validator/src/main/resources/rawfile/H264_AAC.mkv
...or/acts_validator/src/main/resources/rawfile/H264_AAC.mkv
+0
-0
validator/acts_validator/src/main/resources/rawfile/StarWars10s-1C-44100-2SW.wav
...r/src/main/resources/rawfile/StarWars10s-1C-44100-2SW.wav
+0
-0
validator/acts_validator/src/main/resources/rawfile/test_44100_2.wav
...cts_validator/src/main/resources/rawfile/test_44100_2.wav
+0
-0
未找到文件。
validator/acts_validator/AppScope/app.json
浏览文件 @
eaf9538d
...
...
@@ -10,7 +10,7 @@
"keepAlive"
:
true
,
"singleUser"
:
true
,
"minAPIVersion"
:
9
,
"targetAPIVersion"
:
9
,
"targetAPIVersion"
:
10
,
"car"
:
{
"apiCompatibleVersion"
:
9
,
"singleUser"
:
false
...
...
validator/acts_validator/src/main/ets/pages/Audio/AudioInputRoutingTypeC.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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)
}
}
validator/acts_validator/src/main/ets/pages/Audio/AudioInputRoutingWiredHeadset.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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)
}
}
validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingBT.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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)
}
}
validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingTypeC.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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)
}
}
validator/acts_validator/src/main/ets/pages/Audio/AudioOutputRoutingWiredHeadset.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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)
}
}
validator/acts_validator/src/main/ets/pages/Audio/Audio_index.ets
浏览文件 @
eaf9538d
...
...
@@ -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(){
...
...
validator/acts_validator/src/main/ets/pages/Camera/CameraFlash.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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
validator/acts_validator/src/main/ets/pages/Camera/CameraFormat.ets
已删除
100644 → 0
浏览文件 @
2c753396
/*
* 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
validator/acts_validator/src/main/ets/pages/Camera/CameraOrientation.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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
validator/acts_validator/src/main/ets/pages/Camera/CameraPhotoFormat.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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
validator/acts_validator/src/main/ets/pages/Camera/CameraPreviewFormat.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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
validator/acts_validator/src/main/ets/pages/Camera/CameraSerialPhoto.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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
validator/acts_validator/src/main/ets/pages/Camera/CameraVideo.ets
浏览文件 @
eaf9538d
/*
* Copyright (c) 202
2-202
3 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
validator/acts_validator/src/main/ets/pages/Camera/Camera_index.ets
浏览文件 @
eaf9538d
...
...
@@ -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(){
...
...
validator/acts_validator/src/main/ets/pages/
Audio/ScrollListTest
.ets
→
validator/acts_validator/src/main/ets/pages/
Player/PlayAudio
.ets
浏览文件 @
eaf9538d
/*
* 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)
}
}
/*
* 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
validator/acts_validator/src/main/ets/pages/Player/
ScrollListTest
.ets
→
validator/acts_validator/src/main/ets/pages/Player/
PlayVideo
.ets
浏览文件 @
eaf9538d
/*
* 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)
}
}
/*
* 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
validator/acts_validator/src/main/ets/pages/Player/Player_index.ets
浏览文件 @
eaf9538d
...
...
@@ -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(){
...
...
validator/acts_validator/src/main/ets/pages/common/AudioContainer.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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}`);
}
}
}
validator/acts_validator/src/main/ets/pages/common/CameraFlashContainer.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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}`);
}
}
}
validator/acts_validator/src/main/ets/pages/common/CameraOrientationContainer.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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}`);
}
}
}
validator/acts_validator/src/main/ets/pages/common/Camera
Orientation
.ets
→
validator/acts_validator/src/main/ets/pages/common/Camera
PhotoContainer
.ets
浏览文件 @
eaf9538d
/*
* 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}`);
}
}
}
validator/acts_validator/src/main/ets/pages/common/CameraPreviewFormatContainer.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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}`);
}
}
}
validator/acts_validator/src/main/ets/pages/common/CameraVideoContainer.ets
0 → 100644
浏览文件 @
eaf9538d
/*
* 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}`);
}
}
}
validator/acts_validator/src/main/ets/pages/model/CameraService.ts
已删除
100644 → 0
浏览文件 @
2c753396
/*
* 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
<
camera
.
CameraDevice
>
=
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
validator/acts_validator/src/main/ets/pages/model/DateTimeUtil.ts
已删除
100644 → 0
浏览文件 @
2c753396
/*
* 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
validator/acts_validator/src/main/ets/pages/model/Logger.ts
已删除
100644 → 0
浏览文件 @
2c753396
/*
* 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
validator/acts_validator/src/main/ets/pages/model/MediaUtils.ts
已删除
100644 → 0
浏览文件 @
2c753396
/*
* 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
validator/acts_validator/src/main/ets/pages/model/RecordModel.ts
已删除
100644 → 0
浏览文件 @
2c753396
/*
* 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
validator/acts_validator/src/main/resources/base/media/icon_pause.svg
0 → 100644
浏览文件 @
eaf9538d
<?xml version="1.0" encoding="UTF-8"?>
<svg
width=
"24px"
height=
"24px"
viewBox=
"0 0 24 24"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
>
<title>
icon_pause
</title>
<defs>
<path
d=
"M19.7541071,9.806969 L8.736431,3.33971866 C7.54502607,2.64037754 6.02158251,3.05539763 5.33372456,4.26669198 C5.11509768,4.65168644 5,5.08840778 5,5.53296109 L5,18.4674618 C5,19.866144 6.11523809,21 7.490954,21 C7.92820775,21 8.35775814,20.8829809 8.736431,20.6607042 L19.7541071,14.1934539 C20.945512,13.4941127 21.3537175,11.9452367 20.6658595,10.7339423 C20.4472326,10.3489479 20.1327799,10.0292457 19.7541071,9.806969 Z"
id=
"path-1"
></path>
</defs>
<g
id=
"icon_pause"
stroke=
"none"
stroke-width=
"1"
fill=
"none"
fill-rule=
"evenodd"
>
<mask
id=
"mask-2"
fill=
"white"
>
<use
xlink:href=
"#path-1"
></use>
</mask>
<use
id=
"形状结合"
fill=
"#FFFFFF"
xlink:href=
"#path-1"
></use>
</g>
</svg>
\ No newline at end of file
validator/acts_validator/src/main/resources/base/media/icon_play.svg
0 → 100644
浏览文件 @
eaf9538d
<?xml version="1.0" encoding="UTF-8"?>
<svg
width=
"24px"
height=
"24px"
viewBox=
"0 0 24 24"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
>
<title>
icon_play
</title>
<defs>
<path
d=
"M7.5,3.5 C8.32842712,3.5 9,4.17157288 9,5 L9,19 C9,19.8284271 8.32842712,20.5 7.5,20.5 C6.67157288,20.5 6,19.8284271 6,19 L6,5 C6,4.17157288 6.67157288,3.5 7.5,3.5 Z M16.5,3.5 C17.3284271,3.5 18,4.17157288 18,5 L18,19 C18,19.8284271 17.3284271,20.5 16.5,20.5 C15.6715729,20.5 15,19.8284271 15,19 L15,5 C15,4.17157288 15.6715729,3.5 16.5,3.5 Z"
id=
"path-1"
></path>
</defs>
<g
id=
"icon_play"
stroke=
"none"
stroke-width=
"1"
fill=
"none"
fill-rule=
"evenodd"
>
<mask
id=
"mask-2"
fill=
"white"
>
<use
xlink:href=
"#path-1"
></use>
</mask>
<use
id=
"Combined-Shape"
fill=
"#FFFFFF"
xlink:href=
"#path-1"
></use>
</g>
</svg>
\ No newline at end of file
validator/acts_validator/src/main/resources/base/profile/main_pages.json
浏览文件 @
eaf9538d
...
...
@@ -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"
,
...
...
validator/acts_validator/src/main/resources/rawfile/H264_AAC.mkv
0 → 100644
浏览文件 @
eaf9538d
文件已添加
validator/acts_validator/src/main/resources/rawfile/StarWars10s-1C-44100-2SW.wav
0 → 100644
浏览文件 @
eaf9538d
文件已添加
validator/acts_validator/src/main/resources/rawfile/test_44100_2.wav
0 → 100644
浏览文件 @
eaf9538d
文件已添加
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录