!380 fix: remove ohos.multimedia.medialibrary sample

Merge pull request !380 from AlgoIdeas/master
This commit is contained in:
openharmony_ci 2024-07-30 07:59:24 +00:00 committed by Gitee
commit b887bc0135
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
430 changed files with 0 additions and 24908 deletions

View File

@ -1,11 +0,0 @@
/node_modules
/oh_modules
/local.properties
/.idea
**/build
/.hvigor
.cxx
/.clangd
/.clang-format
/.clang-tidy
**/.test

View File

@ -1,26 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
{
"app": {
"bundleName": "com.unionman.distributedvideoplayer",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:app_icon",
"label": "$string:app_name"
}
}

View File

@ -1,8 +0,0 @@
{
"string": [
{
"name": "app_name",
"value": "DistributedVideoPlayer"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,122 +0,0 @@
# 分布式视频播放器
### 介绍
本示例使用medialibrary获取本地视频文件资源并通过AVPlayer完成了视频的播放、暂停、跳转、倍速等功能并使用DeviceManager完成了分布式设备列表的显示和分布式能力完成了视频播放状态的跨设备协同。
本示例用到了文件存储管理能力接口[@ohos.fileio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-fileio.md)
媒体查询接口[@ohos.mediaquery](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-mediaquery.md)
分布式键值数据库接口[@ohos.data.distributedKVStore](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-distributed-data.md)
音视频相关媒体业务能力接口[@ohos.multimedia.media](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-media.md)
分布式设备管理能力接口(设备管理)实现设备之间的kvStore对象的数据传输交互[@ohos.distributedHardware.deviceManager](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-device-manager.md)
应用持久化轻量级数据接口[@ohos.data.preferences](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-data-preferences.md)
屏幕截图接口[@ohos.screenshot](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-screenshot.md)
### 效果预览
| 首页 | 视频列表 |
| ------------------------------------- | ---------------------------------- |
| ![](screenshots/Index.jpeg) | ![](screenshots/VideoList.jpeg) |
| **设备弹窗** | **设置** |
| ![](screenshots/DeviceDialog.jpeg) | ![](screenshots/Settings.jpeg) |
使用说明
1. 首次进入应用会弹出权限弹窗,需要进行授权;
1. 播放视频源可使用hdc命令将视频推到storage/media/100/local/files/Videos路径下并重启
1. **单击**播放键/暂停键或**双击**界面控制**播放/暂停**
2. 点击进度条或左右滑动**操控进度**
3. 点击右上角流转按钮,即可弹出设备选择框;
3. 在设备选择框中点击对端设备名称,拉起对端应用;
3. 对端应用启动后,可在任意一端中操作应用,两端应用可实现数据实时同步;
3. 在设备选择框中选中本机即可关闭对端应用;
3. 点击右上角设置按钮,可对流转模式及分布式认证设备进行设置管理;
### 工程目录
```
entry/src/main/ets/
|---pages
| |---Index.ets // 首页
| |---Settings.ets // 设置页
|---model
| |---DistributedDataModel.ts // 封装分布式数据类
| |---Logger.ets // 日志工具
| |---KvStoreModel.ets // kvstore对象操作类
| |---RemoteDeviceModel.ets // 远程设备操作类
|---common
| |---BasicDataSource.ets // 懒加载数据
| |---DeviceDialog.ets // 分布式设备列表弹窗
| |---ScreenshotDialog.ets // 屏幕截图弹窗
| |---TitleBar.ets // 菜单栏模块(包含远端设备拉起)
|---utils
| |---AVPlayerUtils.ts // 封装AVPlayer工具类
| |---DateTimeUtil.ets // 日期时间工具类
| |---MediaUtils.ts // 媒体库工具类
| |---utils.ets // 自定义工具类
```
### 具体实现
在分布式视频播放器应用中,分布式设备管理包含了分布式设备搜索、分布式设备列表弹窗、远端设备拉起三部分。
首先在分布式组网内搜索设备,然后把设备展示到分布式设备列表弹窗中,最后根据用户的选择拉起远端设备。
#### 分布式设备搜索
通过SUBSCRIBE_ID搜索分布式组网内的远端设备详见startDeviceDiscovery(){}模块[源码参考](https://gitee.com/openharmony/vendor_unionman/blob/master/unionpi_tiger/sample/app/DistributedVideoPlayer/entry/src/main/ets/model/RemoteDeviceModel.ets)。
#### 分布式设备列表弹窗
使用@CustomDialog装饰器来装饰分布式设备列表弹窗[源码参考](https://gitee.com/openharmony/vendor_unionman/blob/master/unionpi_tiger/sample/app/DistributedVideoPlayer/entry/src/main/ets/common/DeviceDialog.ets)。
#### 远端设备拉起
通过startAbility(deviceId)方法拉起远端设备的包,[源码参考](https://gitee.com/openharmony/vendor_unionman/blob/master/unionpi_tiger/sample/app/DistributedVideoPlayer/entry/src/main/ets/common/TitleBar.ets)。
#### 分布式数据管理
(1) 管理分布式数据库
创建一个KVManager对象实例用于管理分布式数据库对象。通过distributedKVStore.createKVManager(config)并通过指定Options和storeId创建并获取KVStore数据库并通过Promise方式返回此方法为异步方法例如this.kvManager.getKVStore(STORE_ID, options).then((store) => {})
(2) 订阅分布式数据变化
通过订阅分布式数据库所有(本地及远端)数据变化实现数据协同[源码参考](https://gitee.com/openharmony/vendor_unionman/blob/master/unionpi_tiger/sample/app/DistributedVideoPlayer/entry/src/main/ets/model/KvStoreModel.ets)。
### 相关权限
[ohos.permission.DISTRIBUTED_DATASYNC](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md#ohospermissiondistributed_datasync)
[ohos.permission.CAPTURE_SCREEN](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md#ohospermissioncapture_screen)
[ohos.permission.READ_MEDIA](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md#ohospermissionread_media)
[ohos.permission.WRITE_MEDIA](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md#ohospermissionwrite_media)
### 依赖
不涉及。
### 约束与限制
1. 本示例仅支持标准系统上运行;
2. 本示例仅支持API9版本SDKSDK版本号(API Version 9 Release),镜像版本号(3.2 Release)
3. 本示例需要使用DevEco Studio 版本号(3.1 Release)才可编译运行;
4. 本示例涉及使用系统接口:@ohos.distributedHardware.deviceManager需要手动替换Full SDK才能编译通过具体操作可参考[替换指南](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/faqs/full-sdk-switch-guide.md)
5. 本示例涉及系统接口,需要配置系统应用签名,可以参考[特殊权限配置方法](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/app-provision-structure.md#修改harmonyappprovision配置文件)把配置文件中的“app-feature”字段信息改为“hos_system_app”。
### 下载
如需单独下载本工程,执行如下命令:
```
git init
git config core.sparsecheckout true
echo unionpi_tiger/sample/app/DistributedVideoPlayer/ > .git/info/sparse-checkout
git remote add origin https://gitee.com/openharmony/vendor_unionman.git
git pull origin master
```

View File

@ -1,43 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
{
"app": {
"signingConfigs": [],
"compileSdkVersion": 9,
"compatibleSdkVersion": 9,
"products": [
{
"name": "default",
"signingConfig": "default",
}
]
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
}
]
}

View File

@ -1,6 +0,0 @@
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test

View File

@ -1,30 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
{
"apiType": 'stageMode',
"buildOption": {
},
"targets": [
{
"name": "default",
"runtimeOS": "OpenHarmony"
},
{
"name": "ohosTest",
}
]
}

View File

@ -1,2 +0,0 @@
// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
export { hapTasks } from '@ohos/hvigor-ohos-plugin';

View File

@ -1,10 +0,0 @@
{
"license": "",
"devDependencies": {},
"author": "",
"name": "entry",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}

View File

@ -1,100 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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';
class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = []
public totalCount(): number {
return 0
}
public getData(index: number): any {
return undefined
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
this.listeners.push(listener)
}
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
this.listeners.splice(pos, 1)
}
}
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded()
})
}
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index)
})
}
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index)
})
}
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index)
})
}
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to)
})
}
}
export default class MediaDataSource extends BasicDataSource {
private dataArray: mediaLibrary.FileAsset[] = []
constructor(data: mediaLibrary.FileAsset[]) {
super()
this.dataArray = data
}
public totalCount(): number {
return this.dataArray.length
}
public getData(index: number): mediaLibrary.FileAsset {
return this.dataArray[index]
}
public addData(index: number, data: mediaLibrary.FileAsset): void {
this.dataArray.splice(index, 0, data)
this.notifyDataAdd(index)
}
public pushData(data: mediaLibrary.FileAsset): void {
this.dataArray.push(data)
this.notifyDataAdd(this.dataArray.length - 1)
}
}

View File

@ -1,101 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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 Logger from '../model/Logger';
import deviceManager from '@ohos.distributedHardware.deviceManager';
const TAG: string = 'DeviceDialog';
@CustomDialog
export struct DeviceDialog {
controller?: CustomDialogController
@StorageLink('deviceLists') deviceLists: Array<deviceManager.DeviceInfo> = AppStorage.Get('deviceLists')
private selectedIndex: number = 0
private selectedIndexChange: (selectedIndex: number) => void = () => {
}
cancel: () => void
build() {
Column() {
Text($r('app.string.choiceDevice'))
.fontSize('32px')
.width('434px')
.fontColor(Color.Black)
.textAlign(TextAlign.Start)
.fontWeight(600)
List() {
ForEach(this.deviceLists, (item: deviceManager.DeviceInfo, index: number | undefined) => {
ListItem() {
Flex({
direction: FlexDirection.Row,
justifyContent: FlexAlign.SpaceBetween,
alignItems: ItemAlign.Center
}) {
Text(item.deviceName)
.fontSize(18)
.width('86%')
.fontColor(Color.Black)
.textAlign(TextAlign.Start)
Radio({ value: '', group: 'radioGroup' })
.width('7%')
.checked(index === this.selectedIndex ? true : false)
.onChange(() => {
Logger.info(TAG, `select device: ${item.deviceId}`)
if (index === this.selectedIndex) {
Logger.info(TAG, 'index === this.selectedIndex')
return
}
this.selectedIndex = index !== undefined ? index : 0
if (this.controller !== undefined) {
this.controller.close()
}
this.selectedIndexChange(this.selectedIndex)
})
}
.height(55)
}
.width('100%')
.height(80)
}, item => item.deviceName)
}
.height('36%')
.width('100%')
Button() {
Text($r('app.string.cancel'))
.width('90%')
.fontSize(21)
.fontColor('#ff0d64fb')
.textAlign(TextAlign.Center)
}
.margin({ bottom: 16 })
.type(ButtonType.Capsule)
.backgroundColor(Color.White)
.onClick(() => {
if (this.controller !== undefined) {
this.controller.close()
this.cancel()
}
})
}
.margin({ bottom: 36 })
.width('500px')
.padding(10)
.backgroundColor(Color.White)
.border({ color: Color.White, radius: 20 })
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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.
*
*/
const SCALE: number = 0.5; // 缩放比例
@CustomDialog
export struct ScreenshotDialog {
screenshotController: CustomDialogController
@Link screenshotUrl: PixelMap
build() {
Column() {
Image(this.screenshotUrl)
}
.borderRadius(10)
.padding(20)
.backgroundColor(Color.White)
.scale({ x: SCALE, y: SCALE })
}
}

View File

@ -1,234 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import router from '@ohos.router';
import screenshot from '@ohos.screenshot';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import promptAction from '@ohos.promptAction';
import deviceManager from '@ohos.distributedHardware.deviceManager';
import Logger from '../model/Logger';
import MediaUtils from '../utils/MediaUtils';
import { DeviceDialog } from '../common/DeviceDialog';
import { RemoteDeviceModel } from '../model/RemoteDeviceModel';
import { ScreenshotDialog } from '../common/ScreenshotDialog';
const TAG = 'TitleBar';
const DATA_CHANGE = 'dataChange';
const EXIT = 'exit';
const ONE_THOUSAND: number = 1000;
@Component
export struct TitleBar {
@Prop title: string
@Prop isLand: boolean
@State selectedIndex: number = 0
@StorageLink('deviceLists') deviceLists: Array<deviceManager.DeviceInfo> = []
@State screenshotUrl: PixelMap = undefined
private startAbilityCallBack: (key) => void
private remoteDeviceModel: RemoteDeviceModel = null
private dialogController: CustomDialogController = null
private mediaUtil: MediaUtils = new MediaUtils()
screenshotDialogController: CustomDialogController = new CustomDialogController({
builder: ScreenshotDialog({ screenshotUrl: $screenshotUrl }),
autoCancel: true,
customStyle: true,
offset: { dx: -100, dy: 100 }
})
aboutToAppear() {
AppStorage.SetOrCreate('deviceLists', this.deviceLists)
}
clearSelectState() {
this.deviceLists = []
if (this.dialogController) {
this.dialogController.close()
this.dialogController = null
}
}
selectDevice() {
Logger.info(TAG, `start ability device:${JSON.stringify(this.deviceLists[this.selectedIndex])}`)
if (this.remoteDeviceModel === null || this.remoteDeviceModel.discoverLists.length <= 0 || this.remoteDeviceModel.deviceLists.includes(this.deviceLists[this.selectedIndex])) {
this.startAbility(this.deviceLists[this.selectedIndex].deviceId)
this.clearSelectState()
return
}
Logger.info(TAG, 'start ability, needAuth')
this.remoteDeviceModel.authenticateDevice(this.deviceLists[this.selectedIndex], (device: deviceManager.DeviceInfo) => {
Logger.info(TAG, 'auth and online finished' + JSON.stringify(device))
this.startAbility(device.deviceId)
})
Logger.info(TAG, 'start ability2 ......')
this.clearSelectState()
}
selectedIndexChange = (index: number) => {
Logger.info(TAG, 'selectedIndexChange')
this.selectedIndex = index
if (this.selectedIndex === 0) {
Logger.info(TAG, 'stop ability')
this.startAbilityCallBack(EXIT)
globalThis.isDistributed = false
if (this.dialogController !== null) {
this.dialogController.close()
}
this.deviceLists = []
return
}
this.selectDevice()
}
/**
* 启动远程设备
* @param deviceId
*/
async startAbility(deviceId) {
Logger.info(TAG, `startAbility deviceId: ${deviceId}`)
await globalThis.context.startAbility({
bundleName: 'com.unionman.distributedvideoplayer',
abilityName: 'EntryAbility',
deviceId: deviceId,
parameters: {
isStage: 'Stage',
deviceID: "remote"
}
}).then((data) => {
Logger.info(TAG, `start ability finished: ${JSON.stringify(data)}`)
promptAction.showToast({ message: "流转成功" })
globalThis.isDistributed = true
// 等待对端KvStore启动再同步数据
setTimeout(() => {
this.startAbilityCallBack(DATA_CHANGE)
}, 2000)
}).catch((err) => {
Logger.error(TAG, `start ability err: ${JSON.stringify(err)}`);
});
}
showDialog() {
// 注册监听回调,发现设备或查找到已认证设备会弹窗显示
this.remoteDeviceModel.registerDeviceListCallback(() => {
Logger.info(TAG, 'registerDeviceListCallback, callback entered')
this.deviceLists = []
this.deviceLists.push({
deviceId: '0',
deviceName: '本机(结束协同)',
deviceType: deviceManager.DeviceType.UNKNOWN_TYPE,
networkId: '',
range: ONE_THOUSAND
})
let deviceTempList = this.remoteDeviceModel.deviceLists.concat(this.remoteDeviceModel.discoverLists)
Logger.info(TAG, `this.remoteDeviceModel.deviceTempList.length${deviceTempList.length}`)
for (let i = 0; i < deviceTempList.length; i++) {
Logger.info(TAG, `device ${i}/${deviceTempList.length} deviceId= ${deviceTempList[i].deviceId}, deviceName= ${deviceTempList[i].deviceName}, deviceType= ${deviceTempList[i].deviceType}`)
this.deviceLists.push(deviceTempList[i])
AppStorage.Set('deviceLists', this.deviceLists)
Logger.info(TAG, 'deviceLists push end')
}
Logger.info(TAG, 'CustomDialogController start')
if (this.dialogController !== null) {
this.dialogController.close()
this.dialogController = null
}
this.dialogController = new CustomDialogController({
builder: DeviceDialog({
cancel: () => {
this.clearSelectState()
},
selectedIndex: this.selectedIndex,
selectedIndexChange: this.selectedIndexChange
}),
cancel: () => {
this.clearSelectState()
},
autoCancel: true,
customStyle: true,
alignment: this.isLand ? DialogAlignment.Center : DialogAlignment.Bottom
})
this.dialogController.open()
Logger.info(TAG, 'CustomDialogController end')
})
}
build() {
Row() {
Image($r("app.media.ic_back"))
.id("back")
.height('60%')
.margin({ right: 4 })
.width(this.isLand ? '6%' : '8%')
.objectFit(ImageFit.Contain)
.onClick(() => {
globalThis.context.terminateSelf()
})
Text(this.title)
.fontColor(Color.White)
.fontSize(22)
.maxLines(1)
Blank()
Image($r("app.media.ic_controlcenter_screenshot_filled"))
.id("screenshot")
.height('60%')
.margin({ right: 8 })
.width(this.isLand ? '6%' : '8%')
.objectFit(ImageFit.Contain)
.onClick(() => {
var screenshotOptions = {};
screenshot.save(screenshotOptions).then((pixelMap: PixelMap) => {
this.screenshotUrl = pixelMap
this.mediaUtil.savePicture(pixelMap)
this.screenshotDialogController.open()
}).catch((err) => {
Logger.error('Failed to save screenshot: ' + JSON.stringify(err));
});
})
Image($r("app.media.ic_hop"))
.id("hop")
.height('60%')
.width(this.isLand ? '6%' : '8%')
.margin({ right: 8 })
.objectFit(ImageFit.Contain)
.onClick(() => {
this.showDialog()
})
Image($r("app.media.ic_settings"))
.id("settings")
.height('60%')
.width(this.isLand ? '6%' : '8%')
.objectFit(ImageFit.Contain)
.onClick(() => {
router.pushUrl({
url: 'pages/Settings'
})
})
}
.width('100%')
.height(this.isLand ? '10%' : '8%')
.constraintSize({ minHeight: 50 })
.alignItems(VerticalAlign.Center)
.padding({ left: 10, right: 10 })
.linearGradient({
direction: GradientDirection.Bottom,
colors: [['#CC000000', 0.0], ['#33000000', 0.66], ['#00000000', 0.99]]
})
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
if (want.parameters !== undefined) {
AppStorage.SetOrCreate('isStage', want.parameters.isStage)
AppStorage.SetOrCreate('deviceID', want.parameters.deviceID)
}
globalThis.context = this.context;
}
onWindowStageCreate(windowStage: window.WindowStage) {
let AtManager = abilityAccessCtrl.createAtManager();
AtManager.requestPermissionsFromUser(this.context, ["ohos.permission.DISTRIBUTED_DATASYNC", "ohos.permission.READ_MEDIA", "ohos.permission.WRITE_MEDIA"])
windowStage.getMainWindowSync().setWindowSystemBarEnable([])
windowStage.loadContent('pages/Index', null);
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default class DistributedDataModel {
public title: string
public currentTime: number
public SpeedIndex: number
public isPlay: boolean
public firstHop: boolean
constructor(title, currentTime, SpeedIndex, isPlay, firstHop) {
this.title = title
this.currentTime = currentTime
this.SpeedIndex = SpeedIndex
this.isPlay = isPlay
this.firstHop = firstHop
}
}

View File

@ -1,94 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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 Logger from './Logger';
import distributedKVStore from '@ohos.data.distributedKVStore';
const TAG = 'KvStoreModel';
const STORE_ID = 'distributedvideoplayer';
export class KvStoreModel {
private kvManager: distributedKVStore.KVManager = undefined;
private kvStore: distributedKVStore.SingleKVStore = undefined;
constructor() {
}
async createKvStore(callback) {
if ((typeof (this.kvStore) !== 'undefined')) {
callback()
return
}
let kvManagerConfig = {
bundleName: 'com.unionman.distributedvideoplayer',
context: globalThis.context
}
Logger.info(TAG, 'createKVManager begin')
this.kvManager = distributedKVStore.createKVManager(kvManagerConfig)
Logger.info(TAG, `createKVManager success, kvManager`)
let options = {
createIfMissing: true, // 当数据库文件不存在时创建数据库
encrypt: false, // 设置数据库文件不加密
backup: false, // 设置数据库文件不备份
autoSync: true, // 设置数据库文件自动同步
kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, // 设置要创建的数据库类型为表示单版本数据库
securityLevel: distributedKVStore.SecurityLevel.S1, // 设置数据库安全级别为低级别
}
Logger.info(TAG, 'kvManager.getKVStore begin')
// 通过指定Options和storeId创建并获取KVStore数据库
this.kvStore = await this.kvManager.getKVStore(STORE_ID, options)
Logger.info(TAG, `getKVStore success, kvStore=${JSON.stringify(this.kvStore)}`)
callback()
Logger.info(TAG, 'kvManager.getKVStore end')
Logger.info(TAG, 'createKVManager end')
}
put(key, value) {
Logger.info(TAG, `kvStore.put ${key}=${value}`)
try {
this.kvStore.put(key, value).then((data) => {
Logger.info(TAG, `kvStore.put ${key} finished, data= ${data}`)
}).catch((err) => {
Logger.error(TAG, `kvStore.put ${key} failed ${err}`)
})
} catch (e) {
Logger.error(TAG, `An unexpected error occurred.code is ${e.code},message is ${e.message}`);
}
}
setOnMessageReceivedListener(msg, callback) {
Logger.info(TAG, `setOnMessageReceivedListener ${msg}`)
this.createKvStore(() => {
Logger.info(TAG, 'kvStore.on(dataChange) begin')
this.kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_REMOTE, (data) => {
Logger.info(TAG, `dataChange, ${JSON.stringify(data)}`)
Logger.info(TAG, `dataChange, insert ${data.insertEntries.length},udpate ${data.updateEntries.length}`)
let entries = data.insertEntries.length > 0 ? data.insertEntries : data.updateEntries
for (let i = 0; i < entries.length; i++) {
if (entries[i].key === msg) {
let value = entries[i].value.value
Logger.info(TAG, `Entries receive${msg} = ${value}`)
callback(value)
return;
}
}
});
Logger.info(TAG, 'kvStore.on(dataChange) end')
})
}
}

View File

@ -1,46 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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 = 0xFF00
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('[DistributedVideoPlayer]')

View File

@ -1,242 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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 Logger from './Logger';
import promptAction from '@ohos.promptAction';
import deviceManager from '@ohos.distributedHardware.deviceManager';
const TAG = 'RemoteDeviceModel';
const RANDOM: number = 65536;
let SUBSCRIBE_ID = 100;
export class RemoteDeviceModel {
public deviceLists: Array<deviceManager.DeviceInfo> = []
public discoverLists: Array<deviceManager.DeviceInfo> = []
private callback: () => void = null
private authCallback: (device: deviceManager.DeviceInfo) => void = null
private deviceManager: deviceManager.DeviceManager = undefined
constructor() {
}
registerDeviceListCallback(callback) {
if (typeof (this.deviceManager) !== 'undefined') {
this.registerDeviceListCallbackImplement(callback)
return
}
Logger.info(TAG, 'deviceManager.createDeviceManager begin')
try {
deviceManager.createDeviceManager("com.unionman.distributedvideoplayer", (error, value) => {
if (error) {
Logger.error(TAG, `createDeviceManager failed.${error}`)
return
}
this.deviceManager = value
this.registerDeviceListCallbackImplement(callback)
Logger.info(TAG, `createDeviceManager callback returned, error= ${error} value= ${JSON.stringify(value)}`)
})
} catch (error) {
Logger.error(TAG, `createDeviceManager throw error, code=${error.code} message=${error.message}`)
}
Logger.info(TAG, 'deviceManager.createDeviceManager end')
}
deviceStateChangeActionOffline(device) {
if (this.deviceLists.length <= 0) {
this.callback()
return
}
for (let j = 0; j < this.deviceLists.length; j++) {
if (this.deviceLists[j].deviceId === device.deviceId) {
this.deviceLists[j] = device
break
}
}
Logger.info(TAG, `offline, device list= ${JSON.stringify(this.deviceLists)}`)
this.callback()
}
changeStateOnline(device) {
this.deviceLists[this.deviceLists.length] = device
Logger.debug(TAG, `online, device list= ${JSON.stringify(this.deviceLists)}`)
this.callback()
}
registerDeviceListCallbackImplement(callback) {
Logger.info(TAG, 'registerDeviceListCallback')
this.callback = callback
if (this.deviceManager === undefined) {
Logger.error(TAG, 'deviceManager has not initialized')
this.callback()
return
}
Logger.info(TAG, 'getTrustedDeviceListSync begin')
try {
let list = this.deviceManager.getTrustedDeviceListSync()
Logger.info(TAG, `getTrustedDeviceListSync end, deviceList= ${JSON.stringify(list)}`)
if (typeof (list) != 'undefined' && typeof (list.length) != 'undefined') {
this.deviceLists = list
}
} catch (error) {
Logger.error(TAG, `getTrustedDeviceListSync throw error, code=${error.code} message=${error.message}`)
}
this.callback()
Logger.info(TAG, `callback finished devices = ${JSON.stringify(this.deviceLists)}`)
try {
this.deviceManager.on('deviceStateChange', (data) => {
if (data === null) {
return
}
Logger.info(TAG, `deviceStateChange data= ${JSON.stringify(data)}`)
switch (data.action) {
case deviceManager.DeviceStateChangeAction.ONLINE:
this.changeStateOnline(data.device)
break;
case deviceManager.DeviceStateChangeAction.READY:
this.discoverLists = []
this.deviceLists.push(data.device)
this.callback()
try {
let list = this.deviceManager.getTrustedDeviceListSync()
if (typeof (list) !== 'undefined' && typeof (list.length) !== 'undefined') {
this.deviceLists = list
}
} catch (error) {
Logger.error(TAG, `getTrustedDeviceListSync throw error, code=${error.code} message=${error.message}`)
}
this.callback()
break;
case deviceManager.DeviceStateChangeAction.OFFLINE:
case deviceManager.DeviceStateChangeAction.CHANGE:
this.deviceStateChangeActionOffline(data.device)
try {
let list = this.deviceManager.getTrustedDeviceListSync()
if (typeof (list) !== 'undefined' && typeof (list.length) !== 'undefined') {
this.deviceLists = list
}
} catch (error) {
Logger.error(TAG, `getTrustedDeviceListSync throw error, code=${error.code} message=${error.message}`)
}
this.callback()
break
default:
break
}
})
this.deviceManager.on('deviceFound', (data) => {
if (data === null) {
return
}
Logger.info(TAG, `deviceFound data=${JSON.stringify(data)}`)
this.deviceFound(data)
})
this.deviceManager.on('discoverFail', (data) => {
Logger.info(TAG, `discoverFail data= ${JSON.stringify(data)}`)
})
this.deviceManager.on('serviceDie', () => {
Logger.error(TAG, 'serviceDie')
})
} catch (error) {
Logger.error(TAG, `on throw error, code=${error.code} message=${error.message}`)
}
this.startDeviceDiscovery()
}
deviceFound(data) {
for (var i = 0;i < this.discoverLists.length; i++) {
if (this.discoverLists[i].deviceId === data.device.deviceId) {
Logger.info(TAG, 'device founded ignored')
return
}
}
this.discoverLists[this.discoverLists.length] = data.device
Logger.info(TAG, `deviceFound self.discoverList= ${JSON.stringify(this.discoverLists)}`)
this.callback()
}
/**
* 通过SUBSCRIBE_ID搜索分布式组网内的设备
*/
startDeviceDiscovery() {
// 生成发现标识,随机数确保每次调用发现接口的标识不一致,且SUBSCRIBE_ID在0到65536之间
SUBSCRIBE_ID = Math.floor(RANDOM * Math.random())
let info = {
subscribeId: SUBSCRIBE_ID, // 发现标识,用于标识不同的发现周期
mode: 0xAA, // 主动模式
medium: 2, // WiFi发现类型
freq: 2, // 高频率
isSameAccount: false, // 是否同账号
isWakeRemote: true, // 是否唤醒设备
capability: 0 // DDMP能力
}
Logger.info(TAG, `startDeviceDiscovery ${SUBSCRIBE_ID}`)
// 当有设备发现时通过deviceFound回调通知给应用程序
try {
this.deviceManager.startDeviceDiscovery(info)
} catch (error) {
Logger.error(TAG, `startDeviceDiscovery throw error, code=${error.code} message=${error.message}`)
}
}
authenticateDevice(device, callBack) {
Logger.info(TAG, `authenticateDevice ${JSON.stringify(device)}`)
for (let i = 0; i < this.discoverLists.length; i++) {
if (this.discoverLists[i].deviceId !== device.deviceId) {
continue
}
let extraInfo = {
'targetPkgName': 'com.unionman.distributedvideoplayer',
'appName': 'Distributed VideoPlayer',
'appDescription': 'Distributed VideoPlayer',
'business': '0'
}
let authParam = {
'authType': 1, //认证类型: 1 - 无账号PIN码认证
'appIcon': '',
'appThumbnail': '',
'extraInfo': extraInfo
}
try {
this.deviceManager.authenticateDevice(device, authParam, (err, data) => {
if (err) {
Logger.error(TAG, `authenticateDevice error: ${JSON.stringify(err)}`)
this.authCallback = null
return
}
Logger.info(TAG, `authenticateDevice succeed: ${JSON.stringify(data)}`)
this.authCallback = callBack
if (this.authCallback !== null) {
this.authCallback(device)
this.authCallback = null
}
})
} catch (error) {
Logger.error(TAG, `authenticateDevice throw error, code=${error.code} message=${error.message}`)
}
}
}
unAuthenticateDevice(device) {
try {
this.deviceManager.unAuthenticateDevice(device);
promptAction.showToast({ message: '解除中,请稍后...', duration: 3000 })
} catch (err) {
Logger.error(TAG, "unAuthenticateDevice errCode:" + err.code + ",errMessage:" + err.message);
}
}
}

View File

@ -1,533 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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 mediaQuery from '@ohos.mediaquery';
import preferences from '@ohos.data.preferences';
import MediaDataSource from '../common/BasicDataSource';
import { TitleBar } from '../common/TitleBar';
import { toTime } from '../utils/utils';
import { RemoteDeviceModel } from '../model/RemoteDeviceModel';
import { KvStoreModel } from '../model/KvStoreModel';
import Logger from '../model/Logger';
import MediaUtils from '../utils/MediaUtils';
import AVPlayerUtils from '../utils/AVPlayerUtils';
import DistributedDataModel from '../model/DistributedDataModel';
const TAG: string = "Index";
const EXIT: string = 'exit';
const DATA_CHANGE: string = 'dataChange';
const PlaybackSpeed: string[] = ['0.75X', '1.0X', '1.25X', '1.75X', '2.0X'];
const PREFERENCES_NAME = 'setting';
let preferenceSetting: preferences.Preferences = null;
@Component
struct localVideoItem {
private media: mediaLibrary.FileAsset
@State pixelMap: PixelMap = undefined
@Link videoIndex: number
@State index: number = 0
event: (event?: ClickEvent) => void
async aboutToAppear() {
let size = { width: 128, height: 80 }
this.pixelMap = await this.media.getThumbnail(size)
}
build() {
Row({ space: 10 }) {
Image(this.pixelMap)
.height(80)
.aspectRatio(1.6)
.objectFit(ImageFit.Cover)
.borderRadius(10)
Text(this.media.displayName.replace('.mp4', ''))
.width(172)
.fontSize(14)
.fontColor(this.videoIndex === this.index ? '#E5007DFF' : '#FFFFFF')
}
.width(330)
.height(100)
.padding(10)
.borderRadius(20)
.backgroundColor('#464646')
.alignItems(VerticalAlign.Center)
.onClick(this.event)
}
}
@Entry
@Component
struct Index {
@State tabsIndex: number = 0
@State @Watch('resetVideo') videoIndex: number = 0
@State @Watch('initVideo') title: string = ''
@State @Watch('setSpeed') SpeedIndex: number = 1
@State @Watch('dataChange') isPlay: boolean = false
// 是否显示控制栏
@State @Watch('showControlBarEvent') controls: number = Visibility.Visible;
// 是否显示侧边栏
@State showSideBar: boolean = false
@State showPlaybackProgress: boolean = false
@State currentTime: number = 0
@State duration: number = 0
@State kvStoreModel: KvStoreModel = new KvStoreModel()
@State ratio: number = 1.0
// 是否横屏
@State isLand: boolean = false
// 是否正在加载
@State isLoading: boolean = true;
// 流转模式
@StorageLink('continuationMode') continuationMode: string = 'continuation'
// 控制栏定时器id
private controlBarTimeoutID: number
private tabsController: TabsController = new TabsController()
private remoteDeviceModel: RemoteDeviceModel = new RemoteDeviceModel()
private mediaDataSource: MediaDataSource = new MediaDataSource([])
private mediaUtil: MediaUtils = new MediaUtils()
private mediaList: Array<mediaLibrary.FileAsset> = []
private mXComponentController: XComponentController = new XComponentController()
private surfaceId: string = ''
private avPlayer: AVPlayerUtils = new AVPlayerUtils()
private fileAsset: mediaLibrary.FileAsset = undefined
private fd: number = undefined
private listener = mediaQuery.matchMediaSync('screen and (min-aspect-ratio: 1.5) or (orientation: landscape)')
onLand = (mediaQueryResult) => {
Logger.info(TAG, `onLand: mediaQueryResult.matches= ${mediaQueryResult.matches}`)
if (mediaQueryResult.matches) {
this.isLand = true
} else {
this.isLand = false
}
}
startX: number
startY: number
moveX: number
moveY: number
@Builder TabBuilder(index: number, text: string) {
Column() {
Text(text)
.fontColor(Color.White)
.fontSize(24)
.fontFamily('HarmonyHeiTi')
Divider()
.width('75%')
.strokeWidth(5)
.color('#007Dff')
.opacity(this.tabsIndex === index ? 1 : 0)
}
}
async aboutToAppear() {
this.getVideos()
// 订阅DATA_CHANGE类型的数据变更通知
this.kvStoreModel.setOnMessageReceivedListener(DATA_CHANGE, value => {
Logger.info(TAG, `DATA_CHANGE ${value}`)
if (globalThis.isDistributed) {
if (value.search(EXIT) !== -1) {
Logger.info(TAG, `EXIT ${EXIT}`)
globalThis.context.terminateSelf((error) => {
Logger.error(TAG, `terminateSelf finished, error= ${error}`)
});
} else {
let video = JSON.parse(value)
globalThis.dataChange = true
globalThis.firstHop = video.firstHop
this.title = video.title
this.currentTime = video.currentTime
if (!video.firstHop) {
this.setCurrentTime()
}
this.SpeedIndex = video.SpeedIndex
this.isPlay = video.isPlay
Logger.info(TAG, `title:${this.title},currentTime:${this.currentTime},SpeedIndex:${this.SpeedIndex},isPlay:${this.isPlay},firstHop:${globalThis.firstHop}`)
globalThis.dataChange = false
}
}
})
if (AppStorage.Get('isStage') === 'Stage') {
globalThis.isDistributed = true
}
globalThis.deviceID = AppStorage.Get('deviceID')
this.listener.on('change', this.onLand)
preferenceSetting = await preferences.getPreferences(globalThis.context, PREFERENCES_NAME)
this.continuationMode = <string> await preferenceSetting.get('continuationMode', 'continuation')
}
startAbilityCallBack = (key) => {
Logger.info(TAG, `startAbilityCallBack ${key}`)
if (DATA_CHANGE === key) {
globalThis.deviceID = "local"
globalThis.firstHop = true
let video = new DistributedDataModel(this.title, this.currentTime, this.SpeedIndex, this.isPlay, true)
this.isPlay = false
this.kvStoreModel.put(DATA_CHANGE, JSON.stringify(video))
if (this.continuationMode == 'continuation') {
globalThis.context.terminateSelf()
}
}
if (EXIT === key) {
this.kvStoreModel.put(DATA_CHANGE, EXIT)
}
}
async getVideos() {
this.mediaDataSource['dataArray'] = []
let fileList = await this.mediaUtil.getFileAssetsFromType(mediaLibrary.MediaType.VIDEO)
Logger.info(TAG, 'getVideos fileList:' + JSON.stringify(fileList))
this.mediaList = this.mediaDataSource['dataArray'] = fileList
Logger.info(TAG, 'getVideos mediaList:' + JSON.stringify(this.mediaList))
Logger.info(TAG, 'getVideos mediaDataSource:' + JSON.stringify(this.mediaDataSource['dataArray']))
this.mediaDataSource.notifyDataReload()
if (!globalThis.isDistributed) {
this.title = this.mediaList[this.videoIndex].displayName.replace('.mp4', '')
}
}
dataChange() {
Logger.info(TAG, `dataChange, title = ${this.title}, currentTime = ${this.currentTime}, SpeedIndex = ${this.SpeedIndex}, isPlay = ${this.isPlay}`)
if (this.isPlay) {
this.playVideo()
} else {
this.avPlayer.pause()
this.controls = Visibility.Visible
clearTimeout(this.controlBarTimeoutID)
}
this.controls = Visibility.Visible
this.distributedDataSync()
}
distributedDataSync() {
if (globalThis.isDistributed && !globalThis.firstHop && !globalThis.dataChange) {
let video = new DistributedDataModel(this.title, this.currentTime, this.SpeedIndex, this.isPlay, false)
this.kvStoreModel.put(DATA_CHANGE, JSON.stringify(video))
}
}
showControlBarEvent() {
if (this.controls == Visibility.Visible) {
this.controlBarTimeoutID = setTimeout(() => {
this.controls = Visibility.Hidden
}, 5000)
}
}
async initVideo() {
Logger.info(TAG, 'initVideo')
try {
this.mediaList.forEach((file, index) => {
if (file.displayName.replace('.mp4', '') === this.title) {
this.fileAsset = file
this.videoIndex = index
}
})
let fdPath = await this.prepareVideo()
await this.avPlayer.initVideoPlayer(fdPath, this.surfaceId)
if (globalThis.firstHop && globalThis.isDistributed) {
this.setCurrentTime()
}
if (globalThis.firstHop && globalThis.deviceID === "remote") {
this.dataChange()
globalThis.firstHop = false
let video = new DistributedDataModel(this.title, this.currentTime, this.SpeedIndex, this.isPlay, false)
this.kvStoreModel.put(DATA_CHANGE, JSON.stringify(video))
}
} catch (error) {
Logger.info(TAG, `initVideo error ${JSON.stringify(error)}`)
}
}
async prepareVideo() {
Logger.info(TAG, 'prepareVideo')
this.fd = await this.fileAsset.open('Rw')
this.ratio = this.fileAsset.width / this.fileAsset.height
this.mXComponentController.setXComponentSurfaceSize({
surfaceWidth: this.fileAsset.width,
surfaceHeight: this.fileAsset.height
})
this.surfaceId = this.mXComponentController.getXComponentSurfaceId()
this.isLoading = false
this.duration = this.fileAsset.duration / 1000
return 'fd://' + this.fd
}
async resetVideo() {
Logger.info(TAG, 'resetVideo')
if (globalThis.firstHop) {
return
}
this.SpeedIndex = 1
this.currentTime = 0
this.isLoading = true
await this.fileAsset.close(this.fd)
this.fileAsset = this.mediaList[this.videoIndex]
this.title = this.fileAsset.displayName.replace('.mp4', '')
this.isPlay = false
this.distributedDataSync()
let fdPath = await this.prepareVideo()
await this.avPlayer.reset(fdPath)
}
async playVideo() {
Logger.info(TAG, 'playVideo')
if (globalThis.firstHop) {
return
}
this.avPlayer.setTimeUpdateCallBackCallBack((time: number) => {
this.currentTime = time / 1000
})
this.avPlayer.play()
this.isPlay = true
this.showControlBarEvent()
}
aboutToDisappear() {
this.clearVideoPlayer()
}
clearVideoPlayer() {
Logger.info(TAG, 'clearVideoPlayer')
if (this.avPlayer) {
this.avPlayer.stop()
this.avPlayer.release()
}
if (this.fileAsset) {
this.fileAsset.close(this.fd)
}
}
setCurrentTime() {
Logger.info(TAG, 'setCurrentTime')
this.avPlayer.seek(this.currentTime)
this.isLoading = false
this.distributedDataSync()
}
setSpeed() {
Logger.info(TAG, 'setSpeed')
this.avPlayer.setSpeed(this.SpeedIndex)
this.distributedDataSync()
}
build() {
SideBarContainer(SideBarContainerType.Overlay) {
Tabs({ controller: this.tabsController }) {
TabContent() {
Scroll() {
Column({ space: 10 }) {
LazyForEach(this.mediaDataSource, (item, index) => {
localVideoItem({ media: item, videoIndex: $videoIndex, index: index, event: () => {
this.videoIndex = index
this.title = item.displayName.replace('.mp4', '')
} })
})
}
.constraintSize({ minHeight: '100%' })
}
.edgeEffect(EdgeEffect.Spring)
.padding(10)
}.tabBar(this.TabBuilder(0, '本地视频'))
}
.backgroundColor('#7F000000')
.vertical(false)
.scrollable(false)
Stack() {
XComponent({
id: 'xComponent',
type: 'surface',
controller: this.mXComponentController
})
.width('100%')
.aspectRatio(this.ratio)
// 控制栏
Column() {
TitleBar({
title: this.title,
isLand: this.isLand,
startAbilityCallBack: this.startAbilityCallBack.bind(this),
remoteDeviceModel: this.remoteDeviceModel,
})
Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceEvenly, alignItems: ItemAlign.Center }) {
Image(this.isPlay ? $r("app.media.ic_pause") : $r("app.media.ic_play"))
.id("playBtn")
.width(36)
.height(36)
.flexShrink(0)
.margin({ right: 10 })
.onClick(() => {
this.isPlay = !this.isPlay
})
Text(toTime(this.currentTime))
.flexShrink(0)
.fontColor(Color.White)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.None })
Slider({
value: this.currentTime,
min: 0,
max: this.duration,
step: 1,
})
.id("slider")
.blockColor(Color.White)
.trackColor(Color.Gray)
.selectedColor(Color.White)
.onChange((value: number, mode: SliderChangeMode) => {
this.currentTime = value
this.setCurrentTime()
})
Text(toTime(this.duration))
.flexShrink(0)
.fontColor(Color.White)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.None })
Select([{ value: PlaybackSpeed[0] },
{ value: PlaybackSpeed[1] },
{ value: PlaybackSpeed[2] },
{ value: PlaybackSpeed[3] },
{ value: PlaybackSpeed[4] }])
.id("playbackSpeed")
.flexShrink(0)
.backgroundColor('#00000000')
.margin({ left: 10, right: 10 })
.selected(this.SpeedIndex)
.value(PlaybackSpeed[this.SpeedIndex])
.font({ size: 24 })
.fontColor("#E5007DFF")
.selectedOptionFont({ size: 16 })
.selectedOptionFontColor("#E5007DFF")
.optionFont({ size: 16 })
.optionFontColor("#7F007DFF")
.onSelect((index: number, value: string) => {
Logger.info(TAG, `index ${index}`)
this.SpeedIndex = index
})
Image($r("app.media.ic_public_view_list"))
.id("viewList")
.width(36)
.aspectRatio(1)
.flexShrink(0)
.margin({ right: 10 })
.onClick(() => {
this.showSideBar = !this.showSideBar
})
}
.width('100%')
.padding({ left: 10, right: 10 })
.linearGradient({
direction: GradientDirection.Top,
colors: [['#CC000000', 0.0], ['#33000000', 0.66], ['#00000000', 0.99]]
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.SpaceBetween)
.alignItems(HorizontalAlign.Start)
.visibility(this.controls)
if (this.showPlaybackProgress) {
Text(toTime(this.currentTime) + '/' + toTime(this.duration))
.fontColor(Color.White)
.padding(12)
.backgroundColor('#CC000000')
.borderRadius(8)
}
if (this.isLoading) {
Column() {
LoadingProgress()
.height(96)
.width(96)
.color(Color.Grey)
Text("正在加载...")
.fontColor(Color.White)
.fontFamily('HarmonyHeiTi')
.fontSize(14)
}
}
}
.id("container")
.width('100%')
.height('100%')
.backgroundColor(Color.Black)
.onClick(() => {
if (!this.showSideBar) {
this.controls = (this.controls === Visibility.Hidden) ? Visibility.Visible : Visibility.Hidden
} else {
this.showSideBar = false
}
})
.priorityGesture(
GestureGroup(GestureMode.Exclusive,
TapGesture({ count: 2 })
.onAction(() => {
this.isPlay = !this.isPlay
}),
PanGesture({ direction: PanDirection.Left | PanDirection.Right })
.onActionStart((event: GestureEvent) => {
Logger.info(TAG, 'PlaybackEvent Pan start')
this.startX = event.offsetX
})
.onActionUpdate((event: GestureEvent) => {
Logger.info(TAG, 'PlaybackEvent Pan update')
// 右滑
if (event.offsetX - this.startX > 0) {
this.startX = event.offsetX
this.showPlaybackProgress = true
if (this.currentTime === this.duration) {
return
} else {
this.currentTime += 1
}
} // 左滑
else if (event.offsetX - this.startX < 0) {
this.startX = event.offsetX
this.showPlaybackProgress = true
if (this.currentTime === 0) {
return
} else {
this.currentTime -= 1
}
}
})
.onActionEnd(() => {
Logger.info(TAG, 'PlaybackEvent Pan end')
this.showPlaybackProgress = false
this.isLoading = true
this.setCurrentTime()
})
)
)
}
.showSideBar(this.showSideBar)
.showControlButton(false)
.sideBarPosition(SideBarPosition.End)
.sideBarWidth(350)
.minSideBarWidth(200)
.maxSideBarWidth(400)
.onChange((value: boolean) => {
Logger.info('status:' + value)
})
}
}

View File

@ -1,161 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import router from '@ohos.router';
import preferences from '@ohos.data.preferences';
import deviceManager from '@ohos.distributedHardware.deviceManager';
import { RemoteDeviceModel } from '../model/RemoteDeviceModel';
import Logger from '../model/Logger';
const TAG: string = 'Setting';
const PREFERENCES_NAME = 'setting';
let preferenceSetting: preferences.Preferences = null;
@Entry
@Component
struct Setting {
@State deviceLists: Array<deviceManager.DeviceInfo> = []
@StorageLink('continuationMode') @Watch('continuationModeChange') continuationMode: string = 'continuation'
private remoteDeviceModel: RemoteDeviceModel = new RemoteDeviceModel()
async aboutToAppear() {
preferenceSetting = await preferences.getPreferences(globalThis.context, PREFERENCES_NAME)
this.remoteDeviceModel.registerDeviceListCallback(() => {
Logger.info(TAG, 'registerDeviceListCallback, callback entered')
this.deviceLists = this.remoteDeviceModel.deviceLists
Logger.info(TAG, `deviceLists.length${this.deviceLists.length}`)
})
}
async continuationModeChange() {
await preferenceSetting.put('continuationMode', this.continuationMode)
await preferenceSetting.flush()
}
build() {
Column() {
Row() {
Image($r("app.media.ic_back"))
.id("settings_back")
.width('8%')
.height('50%')
.margin({ right: 4 })
.objectFit(ImageFit.Contain)
.onClick(() => {
router.back()
})
Text('设置')
.fontColor(Color.White)
.fontFamily('HarmonyHeiTi')
.fontSize(20)
.maxLines(1)
}
.width('100%')
.height('8%')
.constraintSize({ minHeight: 50 })
.padding({ left: 10, right: 10 })
Row({ space: 10 }) {
Text('流转模式')
.fontColor(Color.White)
.fontFamily('HarmonyHeiTi')
.fontSize(20)
Blank()
Radio({ value: 'continuation', group: 'continuationMode' })
.id("continuation")
.checked(this.continuationMode == 'continuation' ? true : false)
.height(25)
.width(25)
.onChange((isChecked: boolean) => {
if (isChecked) {
this.continuationMode = 'continuation'
}
})
Text('跨端迁移')
.fontColor(Color.White)
.fontFamily('HarmonyHeiTi')
.fontSize(20)
Radio({ value: 'synchronization', group: 'continuationMode' })
.id("synchronization")
.checked(this.continuationMode == 'synchronization' ? true : false)
.height(25)
.width(25)
.onChange((isChecked: boolean) => {
if (isChecked) {
this.continuationMode = 'synchronization'
}
})
Text('多端协同')
.fontColor(Color.White)
.fontFamily('HarmonyHeiTi')
.fontSize(20)
}
.width('100%')
.height(100)
.padding(10)
.borderRadius(20)
.backgroundColor('#464646')
.alignItems(VerticalAlign.Center)
Row() {
Text('认证设备管理')
.fontSize(16)
.fontColor(Color.White)
}
.width('100%')
.padding(10)
Scroll() {
Column() {
ForEach(this.deviceLists, (item: deviceManager.DeviceInfo) => {
Row() {
Text(item.deviceName)
.height('100%')
.fontSize(20)
.fontColor(Color.White)
.fontFamily('HarmonyHeiTi')
Blank()
Button('解除认证')
.onClick(() => {
this.remoteDeviceModel.unAuthenticateDevice(item)
})
}
.width('100%')
.height(80)
.padding(10)
.borderRadius(20)
.backgroundColor('#464646')
.alignItems(VerticalAlign.Center)
})
}
.constraintSize({ minHeight: '100%' })
}
}
.width('100%')
.height('100%')
.padding(10)
.backgroundColor('#7F000000')
}
}

View File

@ -1,161 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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';
const TAG: string = 'AVPlayerUtils';
export default class AVPlayerUtils {
private avPlayer: media.AVPlayer = undefined
private avPlayerState: string = ''
private playPath: string = ''
private timeUpdateCallBack: (time: number) => void = undefined
async initVideoPlayer(playSrc: string, surfaceID: string) {
await this.release()
this.playPath = playSrc
// 创建avPlayer实例对象
this.avPlayer = await media.createAVPlayer()
Logger.info(TAG, 'createVideoPlayer')
// 创建状态机变化回调函数
this.setAVPlayerCallback();
this.avPlayer.url = this.playPath
Logger.info(TAG, 'this.avPlayer.url' + this.avPlayer.url)
this.avPlayer.on('timeUpdate', (time: number) => {
Logger.info(TAG, 'timeUpdate success,and new time is :' + time)
if (this.timeUpdateCallBack) {
this.timeUpdateCallBack(time)
}
});
this.avPlayer.surfaceId = surfaceID
Logger.info(TAG, 'setDisplaySurface')
await this.avPlayer.prepare();
Logger.info(TAG, 'init VideoPlayer finish')
}
// 注册avplayer回调函数
setAVPlayerCallback() {
// seek操作结果回调函数
this.avPlayer.on('seekDone', (seekDoneTime: number) => {
Logger.info(TAG, `AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
})
// error回调监听函数,当avPlayer在操作过程中出现错误时调用 reset接口触发重置流程
this.avPlayer.on('error', err => {
Logger.error(TAG, `Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
this.avPlayer.reset(); // 调用reset重置资源触发idle状态
})
// 状态机变化回调函数
this.avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
switch (state) {
case 'idle': // 成功调用reset接口后触发该状态机上报
Logger.info(TAG, 'AVPlayer state idle called.');
this.avPlayerState = 'idle';
this.avPlayer.release(); // 调用release接口销毁实例对象
break;
case 'initialized': // avplayer 设置播放源后触发该状态上报
Logger.info(TAG, 'AVPlayer state initialized called.');
this.avPlayerState = 'initialized';
break;
case 'prepared': // prepare调用成功后上报该状态机
Logger.info(TAG, 'AVPlayer state prepared called.');
this.avPlayerState = 'prepared';
break;
case 'playing': // play成功调用后触发该状态机上报
Logger.info(TAG, 'AVPlayer state playing called.');
this.avPlayerState = 'playing';
break;
case 'paused': // pause成功调用后触发该状态机上报
Logger.info(TAG, 'AVPlayer state paused called.');
this.avPlayerState = 'paused';
break;
case 'completed': // 播放结束后触发该状态机上报
Logger.info(TAG, 'AVPlayer state completed called.');
this.avPlayerState = 'completed';
break;
case 'stopped': // stop接口成功调用后触发该状态机上报
Logger.info(TAG, 'AVPlayer state stopped called.');
this.avPlayerState = 'stopped';
break;
case 'released':
Logger.info(TAG, 'AVPlayer state released called.');
this.avPlayerState = 'released';
break;
default:
Logger.info(TAG, 'AVPlayer state unknown called.');
break;
}
})
}
async play() {
Logger.info(TAG, 'play')
if (typeof (this.avPlayer) != 'undefined') {
await this.avPlayer.play()
}
}
async seek(time: number) {
Logger.info(TAG, 'seek')
if (typeof (this.avPlayer) != 'undefined' &&
(this.avPlayerState === 'prepared' || this.avPlayerState === 'playing' || this.avPlayerState === 'paused' || this.avPlayerState === 'completed')) {
this.avPlayer.seek(time * 1000)
}
}
async setSpeed(speed: media.PlaybackSpeed) {
Logger.info(TAG, 'setSpeed')
if (typeof (this.avPlayer) != 'undefined') {
this.avPlayer.setSpeed(speed)
}
}
async pause() {
Logger.info(TAG, 'pause')
if (typeof (this.avPlayer) != 'undefined') {
await this.avPlayer.pause()
}
}
async stop() {
Logger.info(TAG, 'stop')
if (typeof (this.avPlayer) != 'undefined') {
await this.avPlayer.stop()
}
}
async reset(playSrc: string) {
Logger.info(TAG, 'reset')
if (typeof (this.avPlayer) != 'undefined') {
this.playPath = playSrc
await this.avPlayer.reset()
this.avPlayer.url = this.playPath
await this.avPlayer.prepare()
}
}
async release() {
Logger.info(TAG, 'release')
if (typeof (this.avPlayer) != 'undefined') {
await this.avPlayer.release()
Logger.info(TAG, 'release success')
}
}
setTimeUpdateCallBackCallBack(callback) {
this.timeUpdateCallBack = callback
}
}

View File

@ -1,66 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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())
}
/**
* 年月日
*/
getDate() {
const DATETIME = new Date()
return this.concatDate(DATETIME.getFullYear(), DATETIME.getMonth() + 1, 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)}`
}
}

View File

@ -1,85 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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 image from '@ohos.multimedia.image';
import fileio from '@ohos.fileio';
import promptAction from '@ohos.promptAction';
import mediaLibrary from '@ohos.multimedia.mediaLibrary';
import Logger from '../model/Logger';
import DateTimeUtil from './DateTimeUtil';
const TAG: string = 'MediaUtils';
export default class MediaUtils {
private mediaList: Array<mediaLibrary.FileAsset> = []
private mediaLib: mediaLibrary.MediaLibrary = undefined
constructor() {
this.mediaLib = mediaLibrary.getMediaLibrary(globalThis.context)
}
async createAndGetFile() {
let mediaTest = mediaLibrary.getMediaLibrary(globalThis.context)
let info = {
prefix: 'IMG_', suffix: '.jpg', directory: mediaLibrary.DirectoryType.DIR_IMAGE
}
let dateTimeUtil = new DateTimeUtil()
let name = `${dateTimeUtil.getDate()}_${dateTimeUtil.getTime()}`
let displayName = `${info.prefix}${name}${info.suffix}`
let publicPath = await mediaTest.getPublicDirectory(info.directory)
Logger.info(TAG, `publicPath = ${publicPath}`)
return await mediaTest.createAsset(mediaLibrary.MediaType.IMAGE, displayName, publicPath)
}
async savePicture(data) {
Logger.info(TAG, `savePicture`)
let packOpts: image.PackingOption = {
format: "image/jpeg", quality: 100
}
let imagePackerApi = image.createImagePacker()
let arrayBuffer = await imagePackerApi.packing(data, packOpts)
let fileAsset = await this.createAndGetFile()
let fd = await fileAsset.open('Rw')
imagePackerApi.release()
try {
await fileio.write(fd, arrayBuffer)
} catch (err) {
Logger.error(`write failed, code is ${err.code}, message is ${err.message}`)
}
await fileAsset.close(fd)
Logger.info(TAG, `write done`)
promptAction.showToast({
message: '图片保存成功', duration: 1000
})
}
async getFileAssetsFromType(mediaType: number) {
Logger.info(TAG, `getFileAssetsFromType,mediaType = ${mediaType}`)
let fileKeyObj = mediaLibrary.FileKey
let fetchOp = {
selections: `${fileKeyObj.MEDIA_TYPE}=?`,
selectionArgs: [`${mediaType}`],
}
let fetchFileResult = await this.mediaLib.getFileAssets(fetchOp)
Logger.info(TAG, `getFileAssetsFromType,fetchFileResult.count = ${fetchFileResult.getCount()}`)
if (fetchFileResult.getCount() > 0) {
this.mediaList = await fetchFileResult.getAllObject()
Logger.info(TAG, `getFileAssetsFromType,fetchFileResult.count = ${JSON.stringify(this.mediaList)}`)
}
return this.mediaList
}
}

View File

@ -1,30 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export function toTime(Number: number): string {
let hour: number
let minute: number
let second: number
hour = Number / 3600 | 0
minute = Number / 60 % 60 | 0
second = Number % 60 | 0
if (hour > 0) {
return (hour < 10 ? '0' + hour : hour.toString()) + ":" + (minute < 10 ? '0' + minute : minute.toString()) + ":" + (second < 10 ? '0' + second : second.toString())
} else {
return (minute < 10 ? '0' + minute : minute.toString()) + ":" + (second < 10 ? '0' + second : second.toString())
}
}

View File

@ -1,87 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"default"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ts",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
],
"requestPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC",
"reason": "$string:distributed_permission",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.CAPTURE_SCREEN"
},
{
"name": "ohos.permission.READ_MEDIA",
"reason": "$string:media_reason",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.WRITE_MEDIA",
"reason": "$string:media_reason",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
}
}
]
}
}

View File

@ -1,8 +0,0 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -1,32 +0,0 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "DistributedVideoPlayer"
},
{
"name": "choiceDevice",
"value": "choiceDevice"
},
{
"name": "cancel",
"value": "cancel"
},
{
"name": "distributed_permission",
"value": "Allow data exchange between different devices"
},
{
"name": "media_reason",
"value": "Allows applications to read media files from external storage"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -1,6 +0,0 @@
{
"src": [
"pages/Index",
"pages/Settings"
]
}

View File

@ -1,32 +0,0 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "DistributedVideoPlayer"
},
{
"name": "choiceDevice",
"value": "choiceDevice"
},
{
"name": "cancel",
"value": "cancel"
},
{
"name": "distributed_permission",
"value": "Allow data exchange between different devices"
},
{
"name": "media_reason",
"value": "Allows applications to read media files from external storage"
}
]
}

View File

@ -1,32 +0,0 @@
{
"string": [
{
"name": "module_desc",
"value": "模块描述"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "分布式视频播放器"
},
{
"name": "choiceDevice",
"value": "选择设备"
},
{
"name": "cancel",
"value": "取消"
},
{
"name": "distributed_permission",
"value": "用于分布式视频播放器进行不同设备间的数据交换"
},
{
"name": "media_reason",
"value": "用于分布式视频播放器访问用户媒体文件中的地理位置信息"
}
]
}

View File

@ -1,398 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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 { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import { Driver, ON } from '@ohos.UiTest';
import resourceManager from '@ohos.resourceManager';
import Logger from '../../../main/ets/model/Logger';
const BUNDLE = 'DistributedVideoPlayer_';
const DELAY_TIME = 1000;
const DELAY_TIME_FiVE = 500;
let driver: Driver = Driver.create();
// 获取AbilityDelegator
let abilityDelegatorRegistry = AbilityDelegatorRegistry.getAbilityDelegator();
// 启动后获取app上下文
let context: Context;
// 启动后获取resourceManager
let manager: resourceManager.ResourceManager;
// 通过 resource 验证有没有这个组件 有的话点击一下
async function checkButtonAndClickWithTextByResource(text: Resource) {
let atom: string = await manager.getStringValue(text);
await driver.assertComponentExist(ON.text(atom));
let button = await driver.findComponent(ON.text(atom));
await button.click();
await driver.delayMs(DELAY_TIME_FiVE);
Logger.info(BUNDLE + atom);
}
// 通过 ID 滑动 slider
async function drawSliderWithId(text: string) {
let atom = text;
await driver.assertComponentExist(ON.id(atom));
let slider = await driver.findComponent(ON.id(atom));
let rect = await slider.getBoundsCenter();
await driver.drag(rect.x - 100, rect.y, rect.x + 100, rect.y, 800)
await driver.delayMs(DELAY_TIME_FiVE);
Logger.info(BUNDLE + atom);
}
// 通过text验证有没有这个组件 有的话点击一下
async function checkButtonAndClickWithText(text: string) {
let atom = text;
await driver.assertComponentExist(ON.text(atom));
let button = await driver.findComponent(ON.text(atom));
await button.click();
await driver.delayMs(DELAY_TIME);
Logger.info(BUNDLE + atom);
}
// 通过id验证有没有这个组件 有的话点击一下
async function checkButtonAndClickWithID(text: string) {
let atom = text;
await driver.assertComponentExist(ON.id(atom));
let button = await driver.findComponent(ON.id(atom));
await button.click();
await driver.delayMs(DELAY_TIME_FiVE);
Logger.info(BUNDLE + atom);
}
// 通过id验证有没有这个组件 有的话点击一下
async function checkButtonAndDoubleClickWithID(text: string) {
let atom = text;
await driver.assertComponentExist(ON.id(atom));
let button = await driver.findComponent(ON.id(atom));
await button.doubleClick();
await driver.delayMs(DELAY_TIME_FiVE);
Logger.info(BUNDLE + atom);
}
// 展开Select并选择
async function clickSelectIDAndSelectText(toggleId: string, selectText: string) {
{ //展开
let atom = toggleId;
await checkButtonAndClickWithID(atom);
}
{ //选择
let atom = selectText;
await checkButtonAndClickWithText(atom);
}
}
export default function abilityTest() {
describe('ActsAbilityTest', () => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
})
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
})
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
})
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
})
it("assertContain", 0, () => {
Logger.info("Sample_DistributedVideoPlayer test start")
/**
* 打开应用
*/
it(BUNDLE + 'StartAbility_001', 0, async (done: Function) => {
let testName = 'StartAbility';
Logger.info(BUNDLE + testName + ' begin');
let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
try {
await abilityDelegator.startAbility({
bundleName: 'com.unionman.distributedvideoplayer',
abilityName: 'EntryAbility'
})
context = abilityDelegatorRegistry.getAppContext();
manager = context.resourceManager;
done();
} catch (exception) {
Logger.info(BUNDLE, `StartAbility_001 end ${JSON.stringify(exception)}`);
expect(0).assertEqual(exception.code);
done();
}
Logger.info(BUNDLE + testName + ' end');
})
/**
* 获取权限
*/
it(BUNDLE + 'RequestPermissionFunction_001', 0, async () => {
let testName = 'RequestPermissionFunction';
Logger.info(BUNDLE + testName + ' begin');
await driver.delayMs(DELAY_TIME);
// 获取多设备协同权限
await checkButtonAndClickWithTextByResource($r('app.string.permit'));
// 获取文件读写权限
await checkButtonAndClickWithTextByResource($r('app.string.permit'));
Logger.info(BUNDLE + testName + ' end');
})
/**
* 关闭应用
*/
it(BUNDLE + 'StopAbility_001', 0, async (done: Function) => {
let testName = 'StopAbility';
Logger.info(BUNDLE + testName + ' begin');
try {
await checkButtonAndClickWithID("back");
await driver.delayMs(DELAY_TIME);
done();
} catch (exception) {
Logger.info(BUNDLE, `StopAbility_001 end ${JSON.stringify(exception)}`);
expect(0).assertEqual(exception.code);
done();
}
Logger.info(BUNDLE + testName + ' end');
})
/**
* 打开应用
*/
it(BUNDLE + 'StartAbility_002', 0, async (done: Function) => {
let testName = 'StartAbility';
Logger.info(BUNDLE + testName + ' begin');
let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
try {
await abilityDelegator.startAbility({
bundleName: 'com.unionman.distributedvideoplayer',
abilityName: 'EntryAbility'
})
done();
} catch (exception) {
Logger.info(BUNDLE, `StartAbility_002 end ${JSON.stringify(exception)}`);
expect(0).assertEqual(exception.code);
done();
}
Logger.info(BUNDLE + testName + ' end');
})
/**
* 单击播放按钮
*/
it(BUNDLE + 'PlayVideo_001', 0, async () => {
let testName = 'PlayVideo';
Logger.info(BUNDLE + testName + ' begin');
await driver.delayMs(DELAY_TIME);
// 播放
await checkButtonAndClickWithID('playBtn');
await driver.delayMs(DELAY_TIME);
// 暂停
await checkButtonAndClickWithID('playBtn');
await driver.delayMs(DELAY_TIME);
Logger.info(BUNDLE + testName + ' end');
});
/**
* 双击页面
*/
it(BUNDLE + 'PlayVideo_002', 0, async () => {
let testName = 'PlayVideo';
Logger.info(BUNDLE + testName + ' begin');
// 播放
await checkButtonAndDoubleClickWithID('container');
await driver.delayMs(DELAY_TIME);
// 暂停
await checkButtonAndDoubleClickWithID('container');
await driver.delayMs(DELAY_TIME);
// 播放
await checkButtonAndDoubleClickWithID('container');
await driver.delayMs(DELAY_TIME);
Logger.info(BUNDLE + testName + ' end');
});
/**
* 滑动Slider进度条
*/
it(BUNDLE + 'Slider_001', 0, async () => {
let testName = 'Slider';
Logger.info(BUNDLE + testName + ' begin');
await drawSliderWithId("slider");
await driver.delayMs(DELAY_TIME);
Logger.info(BUNDLE + testName + ' end');
});
/**
* 左右滑动屏幕
*/
it(BUNDLE + 'Swipe_001', 0, async () => {
let testName = 'Swipe';
Logger.info(BUNDLE + testName + ' begin');
// 左滑
await driver.swipe(500, 200, 200, 200, 600);
await driver.delayMs(DELAY_TIME);
// 右滑
await driver.swipe(200, 200, 500, 200, 600);
await driver.delayMs(DELAY_TIME);
Logger.info(BUNDLE + testName + ' end');
});
/**
* 调整倍速
*/
it(BUNDLE + 'PlaybackSpeed_001', 0, async () => {
let testName = 'PlaybackSpeed';
Logger.info(BUNDLE + testName + ' begin');
// 单击屏幕显示控制栏
await checkButtonAndClickWithID('container');
await driver.delayMs(DELAY_TIME);
// 选择2.0X倍速
await clickSelectIDAndSelectText('playbackSpeed', '2.0X');
await driver.delayMs(DELAY_TIME);
// 单击屏幕显示控制栏
await checkButtonAndClickWithID('container');
// 选择0.75X倍速
await clickSelectIDAndSelectText('playbackSpeed', '0.75X');
await driver.delayMs(DELAY_TIME);
Logger.info(BUNDLE + testName + ' end');
});
/**
* 展开视频列表
*/
it(BUNDLE + 'ShwoVideoList_001', 0, async () => {
let testName = 'ShwoVideoList';
Logger.info(BUNDLE + testName + ' begin');
await driver.delayMs(DELAY_TIME);
// 单击屏幕显示控制栏
await checkButtonAndClickWithID('container');
await driver.delayMs(DELAY_TIME);
// 点击展开视频列表
await checkButtonAndClickWithID("viewList");
await driver.delayMs(DELAY_TIME);
// 单击隐藏视频列表 固定坐标只支持UnionPi-Tiger其他设备需要调整
await driver.click(200, 200);
await driver.delayMs(DELAY_TIME);
Logger.info(BUNDLE + testName + ' end');
});
/**
* 截图
*/
it(BUNDLE + 'Screenshot_001', 0, async () => {
let testName = 'Screenshot';
Logger.info(BUNDLE + testName + ' begin');
await driver.delayMs(DELAY_TIME);
// 单击屏幕显示控制栏
await checkButtonAndClickWithID('container');
await driver.delayMs(DELAY_TIME);
// 单击截图图标
await checkButtonAndClickWithID('screenshot');
await driver.delayMs(DELAY_TIME);
// 单击隐藏截图窗口 固定坐标只支持UnionPi-Tiger其他设备需要调整
await driver.click(800, 200);
await driver.delayMs(DELAY_TIME);
Logger.info(BUNDLE + testName + ' end');
});
/**
* 测试选择设备弹窗是否能正常弹出
*/
it(BUNDLE + 'ShwoDeviceDialog_001', 0, async () => {
let testName = 'ShwoDeviceDialog';
Logger.info(BUNDLE + testName + ' begin');
await driver.delayMs(DELAY_TIME);
// 单击屏幕显示控制栏
await checkButtonAndClickWithID('container');
await driver.delayMs(DELAY_TIME);
// 单击流转图标
await checkButtonAndClickWithID('hop');
await driver.delayMs(DELAY_TIME);
// 点击取消
await checkButtonAndClickWithTextByResource($r('app.string.cancel'));
await driver.delayMs(DELAY_TIME);
Logger.info(BUNDLE + testName + ' end');
});
/**
* 设置流转模式
*/
it(BUNDLE + 'SetContinuationMode_001', 0, async () => {
let testName = 'SetContinuationMode';
Logger.info(BUNDLE + testName + ' begin');
await driver.delayMs(DELAY_TIME);
// 单击屏幕显示控制栏
await checkButtonAndClickWithID('container');
await driver.delayMs(DELAY_TIME);
// 单击设置图标
await checkButtonAndClickWithID('settings');
await driver.delayMs(DELAY_TIME);
// 选择多端协同模式
await checkButtonAndClickWithID('synchronization');
await driver.delayMs(DELAY_TIME);
// 返回
await checkButtonAndClickWithID('settings_back');
await driver.delayMs(DELAY_TIME);
Logger.info(BUNDLE + testName + ' end');
});
})
})
}

View File

@ -1,21 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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 abilityTest from './Ability.test'
export default function testsuite() {
abilityTest()
}

View File

@ -1,64 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import hilog from '@ohos.hilog';
import { Hypium } from '@ohos/hypium';
import testsuite from '../test/List.test';
import window from '@ohos.window';
export default class TestAbility extends UIAbility {
onCreate(want, launchParam) {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? '');
var abilityDelegator: any
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
var abilityDelegatorArguments: any
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite)
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
windowStage.loadContent('testability/pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s',
JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
}
onForeground() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
}
onBackground() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
}
}

View File

@ -1,53 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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';
@Entry
@Component
struct Index {
aboutToAppear() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility index aboutToAppear');
}
@State message: string = 'Hello World'
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button() {
Text('next page')
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
.type(ButtonType.Capsule)
.margin({
top: 20
})
.backgroundColor('#0D9FFB')
.width('35%')
.height('5%')
.onClick(() => {
})
}
.width('100%')
}
.height('100%')
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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';
import TestRunner from '@ohos.application.testRunner';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
var abilityDelegator = undefined
var abilityDelegatorArguments = undefined
async function onAbilityCreateCallback() {
hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback');
}
async function addAbilityMonitorCallback(err: any) {
hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
}
export default class OpenHarmonyTestRunner implements TestRunner {
constructor() {
}
onPrepare() {
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare ');
}
async onRun() {
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run');
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
var testAbilityName = abilityDelegatorArguments.bundleName + '.TestAbility'
let lMonitor = {
abilityName: testAbilityName,
onAbilityCreate: onAbilityCreateCallback,
};
abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
var cmd = 'aa start -d 0 -a TestAbility' + ' -b ' + abilityDelegatorArguments.bundleName
var debug = abilityDelegatorArguments.parameters['-D']
if (debug == 'true') {
cmd += ' -D'
}
hilog.info(0x0000, 'testTag', 'cmd : %{public}s', cmd);
abilityDelegator.executeShellCommand(cmd,
(err: any, d: any) => {
hilog.info(0x0000, 'testTag', 'executeShellCommand : err : %{public}s', JSON.stringify(err) ?? '');
hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.stdResult ?? '');
hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.exitCode ?? '');
})
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end');
}
}

View File

@ -1,52 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
{
"module": {
"name": "entry_test",
"type": "feature",
"description": "$string:module_test_desc",
"mainElement": "TestAbility",
"deviceTypes": [
"default"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:test_pages",
"abilities": [
{
"name": "TestAbility",
"srcEntry": "./ets/testability/TestAbility.ets",
"description": "$string:TestAbility_desc",
"icon": "$media:icon",
"label": "$string:TestAbility_label",
"exported": true,
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"skills": [
{
"actions": [
"action.system.home"
],
"entities": [
"entity.system.home"
]
}
]
}
]
}
}

View File

@ -1,8 +0,0 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -1,24 +0,0 @@
{
"string": [
{
"name": "module_test_desc",
"value": "test ability description"
},
{
"name": "TestAbility_desc",
"value": "the test ability"
},
{
"name": "TestAbility_label",
"value": "test label"
},
{
"name": "permit",
"value": "permit"
},
{
"name": "cancel",
"value": "cancel"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -1,5 +0,0 @@
{
"src": [
"testability/pages/Index"
]
}

View File

@ -1,24 +0,0 @@
{
"string": [
{
"name": "module_test_desc",
"value": "test ability description"
},
{
"name": "TestAbility_desc",
"value": "the test ability"
},
{
"name": "TestAbility_label",
"value": "test label"
},
{
"name": "permit",
"value": "permit"
},
{
"name": "cancel",
"value": "cancel"
}
]
}

View File

@ -1,24 +0,0 @@
{
"string": [
{
"name": "module_test_desc",
"value": "test ability description"
},
{
"name": "TestAbility_desc",
"value": "the test ability"
},
{
"name": "TestAbility_label",
"value": "test label"
},
{
"name": "permit",
"value": "允许"
},
{
"name": "cancel",
"value": "取消"
}
]
}

View File

@ -1,6 +0,0 @@
{
"hvigorVersion": "2.1.1",
"dependencies": {
"@ohos/hvigor-ohos-plugin": "2.1.1"
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
export { appTasks } from '@ohos/hvigor-ohos-plugin';

View File

@ -1,48 +0,0 @@
#!/bin/bash
# ----------------------------------------------------------------------------
# Hvigor startup script, version 1.0.0
#
# Required ENV vars:
# ------------------
# NODE_HOME - location of a Node home dir
# or
# Add /usr/local/nodejs/bin to the PATH environment variable
# ----------------------------------------------------------------------------
HVIGOR_APP_HOME=$(dirname $(readlink -f $0))
HVIGOR_WRAPPER_SCRIPT=${HVIGOR_APP_HOME}/hvigor/hvigor-wrapper.js
warn() {
echo ""
echo -e "\033[1;33m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
}
error() {
echo ""
echo -e "\033[1;31m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
}
fail() {
error "$@"
exit 1
}
# Determine node to start hvigor wrapper script
if [ -n "${NODE_HOME}" ];then
EXECUTABLE_NODE="${NODE_HOME}/bin/node"
if [ ! -x "$EXECUTABLE_NODE" ];then
fail "ERROR: NODE_HOME is set to an invalid directory,check $NODE_HOME\n\nPlease set NODE_HOME in your environment to the location where your nodejs installed"
fi
else
EXECUTABLE_NODE="node"
which ${EXECUTABLE_NODE} > /dev/null 2>&1 || fail "ERROR: NODE_HOME is not set and not 'node' command found in your path"
fi
# Check hvigor wrapper script
if [ ! -r "$HVIGOR_WRAPPER_SCRIPT" ];then
fail "ERROR: Couldn't find hvigor/hvigor-wrapper.js in ${HVIGOR_APP_HOME}"
fi
# start hvigor-wrapper script
exec "${EXECUTABLE_NODE}" \
"${HVIGOR_WRAPPER_SCRIPT}" "$@"

View File

@ -1,64 +0,0 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Hvigor startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
set WRAPPER_MODULE_PATH=%APP_HOME%\hvigor\hvigor-wrapper.js
set NODE_EXE=node.exe
goto start
:start
@rem Find node.exe
if defined NODE_HOME goto findNodeFromNodeHome
%NODE_EXE% --version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
echo.
echo Please set the NODE_HOME variable in your environment to match the
echo location of your NodeJs installation.
goto fail
:findNodeFromNodeHome
set NODE_HOME=%NODE_HOME:"=%
set NODE_EXE_PATH=%NODE_HOME%/%NODE_EXE%
if exist "%NODE_EXE_PATH%" goto execute
echo.
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
echo.
echo Please set the NODE_HOME variable in your environment to match the
echo location of your NodeJs installation.
goto fail
:execute
@rem Execute hvigor
"%NODE_EXE%" %WRAPPER_MODULE_PATH% %*
if "%ERRORLEVEL%" == "0" goto hvigorwEnd
:fail
exit /b 1
:hvigorwEnd
if "%OS%" == "Windows_NT" endlocal
:end

View File

@ -1,12 +0,0 @@
{
"license": "",
"devDependencies": {
"@ohos/hypium": "1.0.6"
},
"author": "",
"name": "distributedvideoplayer",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}

View File

@ -1,19 +0,0 @@
# DistributedVideoPlayer 测试用例归档
## 用例表
| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 |
| ---------------- | -------------------------------------------- | ---------------------------------------------- | ---------------------- | -------- | -------- |
| 打开应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass |
| 获取权限 | 设备正常运行 | 点击权限弹窗允许按钮 | 授权后成功进入首页 | 是 | Pass |
| 关闭应用 | | 点击左上角返回按钮 | 成功退出应用 | 是 | Pass |
| 打开应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass |
| 单击播放按钮 | 位于首页,控制栏处于显示状态 | 单击播放按钮 | 正常执行 | 是 | Pass |
| 双击页面 | 位于首页 | 双击屏幕 | 正常执行 | 是 | Pass |
| 滑动Slider进度条 | 位于首页,控制栏处于显示状态 | 滑动Slider进度条 | 正常执行 | 是 | Pass |
| 左右滑动屏幕 | | 左右滑动屏幕 | 正常执行 | 是 | Pass |
| 调整倍速 | 位于首页,控制栏处于显示状态,展开倍速选择框 | 点击倍速文本 | 正常执行 | 是 | Pass |
| 切换视频 | 位于首页,控制栏处于显示状态 | 点击视频列表图标 | 展开视频列表侧边栏 | 是 | Pass |
| 截图 | 位于首页,控制栏处于显示状态 | 点击截图按钮 | 成功截图并显示截图窗口 | 是 | Pass |
| 选择设备弹窗 | 位于首页 | 点击流转图标 | 弹出选择设备弹窗 | 是 | Pass |
| 设置流转模式 | 位于首页 | 点击设置图标,进入设置页面后选择“多端协同”模式 | 成功进入设置页面并选择 | 是 | Pass |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

View File

@ -1,24 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
{
"app": {
"bundleName": "com.yarward.factorytest",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:app_icon",
"label": "$string:app_name"
}
}

View File

@ -1,8 +0,0 @@
{
"string": [
{
"name": "app_name",
"value": "factory"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -1,3 +0,0 @@
# factory
factory for OpenHarmony

View File

@ -1,42 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
{
"app": {
"signingConfigs": [
],
"compileSdkVersion": 10,
"compatibleSdkVersion": 9,
"products": [
{
"name": "default",
"signingConfig": "default",
}
]
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
}
]
}

View File

@ -1,33 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
{
"apiType": 'stageMode',
"buildOption": {
"sourceOption": {
"workers": [
"./src/main/ets/pages/workers/fileWorker.ts"
]
}
},
"targets": [
{
"name": "default",
"runtimeOS": "OpenHarmony"
},
{
"name": "ohosTest",
}
]
}

View File

@ -1,2 +0,0 @@
// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
export { hapTasks } from '@ohos/hvigor-ohos-plugin';

View File

@ -1,10 +0,0 @@
{
"license": "",
"devDependencies": {},
"author": "",
"name": "entry",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}

View File

@ -1,92 +0,0 @@
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import prompt from '@ohos.promptAction'
import Logger from '../model/Logger'
import { PswDialog } from './PswDialog'
import { WifiModel } from '../model/WifiModel'
import { WifiView } from './WifiView'
import WifiDataSource from './BasicDataSource'
import wifi from '@ohos.wifiManager'
const TAG = 'AvailableWiFi'
let self = null
@Component
export struct AvailableWifi {
private wifiModel = new WifiModel()
private linkedInfo: wifi.WifiLinkedInfo = null
@StorageLink('wifiList') @Watch('wifiListRefresh') wifiList: Array<wifi.WifiScanInfo> = []
@State wifiDataResource: WifiDataSource = new WifiDataSource(this.wifiList)
@State scanInfo: wifi.WifiScanInfo = undefined
private pswDialogController: CustomDialogController = new CustomDialogController({
builder: PswDialog({ scanInfo: $scanInfo, action: this.onAccept }),
autoCancel: true
})
build() {
List() {
ListItem() {
Row() {
Text($r('app.string.available_wlan'))
.fontSize(22)
.layoutWeight(1)
}
.id('validWlan')
.width('100%')
}
LazyForEach(this.wifiDataResource, (item, index) => {
ListItem() {
WifiView({ wifi: item })
}
.id(`Wifi${index}`)
.onClick(() => {
Logger.info(TAG, 'wifi click')
this.scanInfo = item
if (this.linkedInfo !== null && item.ssid === this.linkedInfo.ssid) {
prompt.showToast({ message: 'this wifi is connected' })
return
}
if (item.securityType === 0 || item.securityType === 1) {
this.wifiModel.connectNetwork(item, '')
return
}
this.pswDialogController.open()
})
}, item => JSON.stringify(item))
}
.width('100%')
.height('100%')
.padding({ left: 16, right: 16 })
.layoutWeight(1)
.divider({ strokeWidth: 1, color: Color.Gray, startMargin: 10, endMargin: 10 })
.margin({ top: 10 })
}
onAccept(scanInfo, psw) {
Logger.info(TAG, 'connect wifi')
self.wifiModel.connectNetwork(scanInfo, psw)
}
aboutToAppear() {
self = this
}
wifiListRefresh() {
this.wifiDataResource['dataArray'] = this.wifiList
this.wifiDataResource.notifyDataReload()
}
}

View File

@ -1,89 +0,0 @@
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import wifi from '@ohos.wifiManager'
import Logger from '../model/Logger'
export default class WifiDataSource {
private listeners: DataChangeListener[] = []
private dataArray: wifi.WifiScanInfo[] = []
constructor(data: wifi.WifiScanInfo[]) {
this.dataArray = data
}
public totalCount(): number {
return this.dataArray.length
}
public getData(index: number): wifi.WifiScanInfo {
return this.dataArray[index]
}
public addData(index: number, data: wifi.WifiScanInfo): void {
this.dataArray.splice(index, 0, data)
this.notifyDataAdd(index)
}
public pushData(data: wifi.WifiScanInfo): void {
this.dataArray.push(data)
this.notifyDataAdd(this.dataArray.length - 1)
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
Logger.info('add listener')
this.listeners.push(listener)
}
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const POS = this.listeners.indexOf(listener)
if (POS >= 0) {
Logger.info('remove listener')
this.listeners.splice(POS, 1)
}
}
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded()
})
}
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index)
})
}
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index)
})
}
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index)
})
}
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to)
})
}
}

View File

@ -1,66 +0,0 @@
/*
* 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 data_preferences from '@ohos.data.preferences';
export default class FirstDialog{
static ChooseDialog = async (StepTips:string,name: string)=>{
let Test = null;
let context =null;
context = globalThis.getContext();
let preferences;
let promise = data_preferences.getPreferences(context,'mystore');
await promise.then((object) => {
preferences = object;
});
promise = preferences.get(name, 0);
await promise.then((data) => {
Test = data;
console.info("Succeeded in getting value of 'startup'. Data: " + data);
});
if(Test != 1) {
AlertDialog.show(
{
title: '操作提示',
message: StepTips,
primaryButton: {
value: '不再提醒',fontColor:Color.Grey,
action: () => {
let promise = preferences.put(name, 1);
promise.then(() => {
console.info("Succeeded in putting value of 'test'.");
});
promise = preferences.flush();
promise.then(() => {
console.info("Succeeded in flushing.");
});
}
},
secondaryButton: {
value: '我已知晓',
action: () => {
}
},
cancel: () => {
}
}
)
}
return;
}
}

View File

@ -1,44 +0,0 @@
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@Component
export struct InfoView {
private infoList: Array<any> = []
build() {
Column() {
ForEach(this.infoList, (item, index) => {
Column() {
Text(item.key)
.fontColor(Color.Black)
.fontSize(20)
.width('100%')
Text(item.value)
.fontColor(Color.Black)
.fontSize(20)
.width('100%')
.margin({ top: 5, bottom: 5 })
if (index < this.infoList.length - 1) {
Divider().color(Color.Grey)
}
}
.padding(5)
}, item => JSON.stringify(item))
}
.margin(10)
.border({ width: 1, color: Color.Gray, radius: 15 })
}
}

View File

@ -1,90 +0,0 @@
/*
* 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 bluetooth from '@ohos.bluetooth'
import logger from '../Model/Logger'
const TAG: string = 'PinDialog'
@CustomDialog
export struct PinDialog {
private controller?: CustomDialogController
private data: bluetooth.PinRequiredParam | null = null
@State titleText: string = ''
@State pinCode: string = ''
@Builder choiceText(message: Resource, handlerClick) {
Text(message)
.width('50%')
.fontSize(30)
.textAlign(TextAlign.Center)
.fontColor('#ff0742ef')
.onClick(handlerClick)
}
aboutToAppear() {
this.titleText = `"${this.data.deviceId}"要与您配对。请确认此配对码已在"${this.data.deviceId}"上直接显示,且不是手动输入的。`
this.pinCode = JSON.stringify(this.data.pinCode)
}
build() {
Column({ space: 10 }) {
Text($r('app.string.match_request'))
.fontSize(30)
.alignSelf(ItemAlign.Start)
Text(this.titleText)
.alignSelf(ItemAlign.Start)
.margin({ top: 20 })
.fontSize(21)
Text(this.pinCode)
.fontSize(40)
.fontWeight(FontWeight.Bold)
.margin({ top: 20 })
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
Checkbox({ name: 'checkbox' })
.select(false)
.selectedColor('#ff3d6fb8')
.key('checkBox')
Text($r('app.string.grant_permission'))
.fontSize(15)
.margin({ left: 3, top: 6 })
}
.alignSelf(ItemAlign.Start)
.width('95%')
.margin({ top: 5 })
Row() {
this.choiceText($r('app.string.cancel'), () => {
bluetooth.setDevicePairingConfirmation(this.data.deviceId, false)
logger.info(TAG, `setDevicePairingConfirmation = ${bluetooth.setDevicePairingConfirmation(this.data.deviceId, false)}`)
this.controller.close()
})
Divider()
.vertical(true)
.height(32)
this.choiceText($r('app.string.match'), () => {
bluetooth.setDevicePairingConfirmation(this.data.deviceId, true)
logger.info(TAG, `setDevicePairingConfirmation = ${bluetooth.setDevicePairingConfirmation(this.data.deviceId, true)}`)
this.controller.close()
})
}
.margin({ top: 20 })
}
.width('100%')
.padding(15)
}
}

View File

@ -1,81 +0,0 @@
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import wifi from '@ohos.wifiManager'
@CustomDialog
export struct PswDialog {
@Link scanInfo: wifi.WifiScanInfo
private psw: string = ''
private controller: CustomDialogController
private action: (scanInfo, psw) => void
build() {
Column() {
Text(this.scanInfo.ssid)
.fontSize(20)
.width('95%')
TextInput({ placeholder: 'input password' })
.id('input')
.type(InputType.Password)
.placeholderColor(Color.Gray)
.fontSize(19)
.margin({ top: 15 })
.width('95%')
.height(36)
.onChange((value: string) => {
this.psw = value
})
Row() {
Button() {
Text($r('app.string.sure'))
.fontColor(Color.Blue)
.fontSize(17)
}
.id('sure')
.layoutWeight(7)
.backgroundColor(Color.White)
.margin(5)
.onClick(() => {
this.controller.close()
this.action(this.scanInfo, this.psw)
})
// 分割线
Text()
.width(1)
.height(35)
.backgroundColor(Color.Black)
Button() {
Text($r('app.string.cancel'))
.fontColor(Color.Red)
.fontSize(17)
}
.layoutWeight(7)
.backgroundColor(Color.White)
.margin(5)
.onClick(() => {
this.controller.close()
})
}
.width('100%')
.margin({ top: '3%' })
}
.padding(15)
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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.
*/
// xxx.ets
@CustomDialog
export struct TipsDialog {
title: string
text: string
controller: CustomDialogController
// 若尝试在CustomDialog中传入多个其他的Controller以实现在CustomDialog中打开另一个或另一些CustomDialog那么此处需要将指向自己的controller放在最后
cancel: () => void
confirm: () => void
build() {
Column() {
Text(this.title).fontSize(20).margin({ top: 10, bottom: 10 })
Text(this.text).fontSize(16).margin({ bottom: 10 })
}
// dialog默认的borderRadius为24vp如果需要使用border属性请和borderRadius属性一起使用。
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import router from '@ohos.router'
// Page title bar
@Component
export struct TitleBar {
private title: Resource | string
build() {
Column() {
Row() {
Image($r('app.media.ic_back'))
.width(20)
.height(20)
.margin({ left: 26 })
.objectFit(ImageFit.Contain)
.onClick(() => {
router.back()
}).id('backBtn')
Text(this.title)
.fontSize(20)
.layoutWeight(1)
.margin({ left: 16 })
.align(Alignment.Start)
Blank()
}
.height(56)
.width('100%')
}
}
}

View File

@ -1,79 +0,0 @@
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Logger from '../model/Logger'
import wifi from '@ohos.wifiManager'
const TAG: string = 'WifiView'
@Component
export struct WifiView {
private wifi: wifi.WifiScanInfo = null
private securityString: Resource = $r('app.string.encryption')
@State isLock: boolean = true
aboutToAppear() {
Logger.debug(TAG, `aboutToAppear ${JSON.stringify(this.wifi)}`)
if (this.wifi) {
if (this.wifi.securityType) {
if (this.wifi.securityType === 0 || this.wifi.securityType === 1) {
this.securityString = $r('app.string.open')
this.isLock = false
}
}
}
}
build() {
Row() {
Column() {
if (this.wifi) {
if (this.wifi.ssid) {
Text(this.wifi.ssid)
.fontSize(20)
.width('50%')
Text(this.wifi.frequency.toString())
.fontSize(20)
.width('50%')
}
}
Text(this.securityString)
.fontSize(18)
.fontColor(Color.Gray)
.width('100%')
}
.layoutWeight(1)
Stack({ alignContent: Alignment.BottomEnd }) {
Image($r('app.media.wifi'))
.height(30)
.width(30)
.objectFit(ImageFit.Contain)
if (this.isLock) {
Image($r('app.media.lock'))
.objectFit(ImageFit.Contain)
.width(15)
.height(15)
}
}
.width(40)
.height(40)
.margin({ right: 10 })
}
.backgroundColor(Color.White)
.width('100%')
.padding(10)
}
}

View File

@ -1,460 +0,0 @@
/**
* 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 deviceInfo from '@ohos.deviceInfo';
import BluetoothModel, { BondState, ProfileConnectionState } from '../Model/BluetoothModel';
import BluetoothDevice from '../Model/BluetoothDevice';
import Logger from '../Model/Logger';
import settings from '@ohos.settings';
const deviceTypeInfo = deviceInfo.deviceType;
const DISCOVERY_DURING_TIME: number = 30000; // 30'
const DISCOVERY_INTERVAL_TIME: number = 3000; // 3'
let debounceTimer = null;
export default class BluetoothDeviceController {
private TAG = 'BluetoothDeviceController '
//state
private isOn: boolean = false;
private enabled: boolean = false;
// paired devices
private pairedDevices: BluetoothDevice[] = [];
// available devices
private isDeviceDiscovering: boolean = false;
private availableDevices: BluetoothDevice[] = [];
private pairPinCode: string = '';
private discoveryStartTimeoutId: number;
private discoveryStopTimeoutId: number;
initData(){
Logger.info(this.TAG + 'start to initData bluetooth');
let isOn = BluetoothModel.isStateOn();
Logger.info(this.TAG + 'initData bluetooth state isOn ' + isOn + ', typeof isOn = ' + typeof (isOn))
if (isOn) {
this.refreshPairedDevices();
}
Logger.info(this.TAG + 'initData save value to app storage. ')
this.isOn = new Boolean(isOn).valueOf()
this.enabled = true
AppStorage.SetOrCreate('bluetoothIsOn', this.isOn);
AppStorage.SetOrCreate('bluetoothToggleEnabled', this.enabled);
AppStorage.SetOrCreate('bluetoothAvailableDevices', this.availableDevices);
return this;
}
subscribe() {
Logger.info(this.TAG + 'subscribe bluetooth state isOn ' + this.isOn)
this.subscribeStateChange();
this.subscribeBluetoothDeviceFind();
this.subscribeBondStateChange();
this.subscribeDeviceConnectStateChange();
BluetoothModel.subscribePinRequired((pinRequiredParam: {
deviceId: string;
pinCode: string;
}) => {
Logger.info(this.TAG + 'bluetooth subscribePinRequired callback. pinRequiredParam = ' + pinRequiredParam.pinCode);
let pairData = this.getAvailableDevice(pinRequiredParam.deviceId);
this.pairPinCode = pinRequiredParam.pinCode;
AppStorage.SetOrCreate('pairData', pairData);
AppStorage.SetOrCreate('pinRequiredParam', pinRequiredParam);
})
return this;
}
unsubscribe(){
Logger.info(this.TAG + 'start to unsubscribe bluetooth');
this.stopBluetoothDiscovery();
if (this.discoveryStartTimeoutId) {
clearTimeout(this.discoveryStartTimeoutId);
}
if (this.discoveryStopTimeoutId) {
clearTimeout(this.discoveryStopTimeoutId);
}
BluetoothModel.unsubscribeBluetoothDeviceFind();
BluetoothModel.unsubscribeBondStateChange();
BluetoothModel.unsubscribeDeviceStateChange();
AppStorage.Delete('BluetoothFailedDialogFlag');
return this;
}
/**
* Set toggle value
*/
toggleValue(isOn: boolean) {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
let curState = BluetoothModel.getState();
if ((curState === 2) === isOn) {
return;
}
this.enabled = false
AppStorage.SetOrCreate('bluetoothToggleEnabled', this.enabled);
Logger.info(this.TAG + 'afterCurrentValueChanged bluetooth state isOn = ' + this.isOn)
if (isOn) {
BluetoothModel.enableBluetooth();
} else {
BluetoothModel.disableBluetooth();
// remove all elements from availableDevices array
this.availableDevices.splice(0, this.availableDevices.length)
}
},500)
}
/**
* Pair device.
*
* @param deviceId device id
* @param success success callback
* @param error error callback
*/
pair(deviceId: string, success?: (pinCode: string) => void, error?: () => void): void {
const device: BluetoothDevice = this.getAvailableDevice(deviceId);
if (device && device.connectionState === BondState.BOND_STATE_BONDING) {
Logger.info(this.TAG + `bluetooth no Aavailable device or device is already pairing.`)
return;
}
// start pairing
BluetoothModel.pairDevice(deviceId);
}
/**
* Confirm pairing.
*
* @param deviceId device id
* @param accept accept or not
* @param success success callback
* @param error error callback
*/
confirmPairing(deviceId: string, accept: boolean): void {
if (accept) {
try {
this.getAvailableDevice(deviceId).connectionState = BondState.BOND_STATE_BONDING;
} catch (err) {
Logger.error(this.TAG + 'confirmPairing =' + JSON.stringify(err));
}
}
// set paring confirmation
BluetoothModel.setDevicePairingConfirmation(deviceId, accept);
}
/**
* Connect device.
* @param deviceId device id
*/
connect(deviceId: string): Array<{
profileId: number;
connectRet: boolean;
}> {
return BluetoothModel.connectDevice(deviceId);
}
/**
* disconnect device.
* @param deviceId device id
*/
disconnect(deviceId: string): Array<{
profileId: number;
disconnectRet: boolean;
}> {
return BluetoothModel.disconnectDevice(deviceId);
}
/**
* Unpair device.
* @param deviceId device id
*/
unpair(deviceId: string): boolean {
AppStorage.SetOrCreate('BluetoothFailedDialogFlag', false);
const result = BluetoothModel.unpairDevice(deviceId);
Logger.info(this.TAG + 'bluetooth paired device unpair. result = ' + result)
this.refreshPairedDevices()
return result;
}
/**
* Refresh paired devices.
*/
refreshPairedDevices() {
let deviceIds: string[] = BluetoothModel.getPairedDeviceIds();
let list: BluetoothDevice[] = []
deviceIds.forEach(deviceId => {
list.push(this.getDevice(deviceId));
});
this.pairedDevices = list;
this.sortPairedDevices();
AppStorage.SetOrCreate('bluetoothPairedDevices', this.pairedDevices);
Logger.info(this.TAG + 'bluetooth paired devices. list length = ' + JSON.stringify(list.length))
}
/**
* Paired device should be shown on top of the list.
*/
private sortPairedDevices() {
Logger.info(this.TAG + 'sortPairedDevices in.')
this.pairedDevices.sort((a: BluetoothDevice, b: BluetoothDevice) => {
if (a.connectionState == ProfileConnectionState.STATE_DISCONNECTED && b.connectionState == ProfileConnectionState.STATE_DISCONNECTED) {
return 0
} else if (b.connectionState == ProfileConnectionState.STATE_DISCONNECTED) {
return -1
} else if (a.connectionState == ProfileConnectionState.STATE_DISCONNECTED) {
return 1
} else {
return 0
}
})
Logger.info(this.TAG + 'sortPairedDevices out.')
}
//---------------------- subscribe ----------------------
/**
* Subscribe bluetooth state change
*/
private subscribeStateChange() {
BluetoothModel.subscribeStateChange((isOn: boolean) => {
Logger.info(this.TAG + 'bluetooth state changed. isOn = ' + isOn)
this.isOn = new Boolean(isOn).valueOf();
this.enabled = true;
Logger.info(this.TAG + 'bluetooth state changed. save value.')
AppStorage.SetOrCreate('bluetoothIsOn', this.isOn);
AppStorage.SetOrCreate('bluetoothToggleEnabled', this.enabled);
if (isOn) {
Logger.info(this.TAG + 'bluetooth state changed. unsubscribe')
this.startBluetoothDiscovery();
} else {
Logger.info(this.TAG + 'bluetooth state changed. subscribe')
this.mStopBluetoothDiscovery();
}
});
}
/**
* Subscribe device find
*/
private subscribeBluetoothDeviceFind() {
BluetoothModel.subscribeBluetoothDeviceFind((deviceIds: Array<string>) => {
Logger.info( this.TAG + 'available bluetooth devices changed.');
deviceIds?.forEach(deviceId => {
let device = this.availableDevices.find((availableDevice) => {
return availableDevice.deviceId === deviceId
})
Logger.info(this.TAG + 'available bluetooth find');
if (!device) {
let pairedDevice = this.pairedDevices.find((pairedDevice) => {
return pairedDevice.deviceId === deviceId
})
if (pairedDevice) {
Logger.info(this.TAG + `available bluetooth is paried.`);
} else {
Logger.info(this.TAG + 'available bluetooth new device found. availableDevices length = ' + this.availableDevices.length);
let newDevice = this.getDevice(deviceId);
this.availableDevices.push(newDevice);
Logger.info(this.TAG + 'available bluetooth new device pushed. availableDevices length = ' + this.availableDevices.length);
}
}
})
AppStorage.SetOrCreate('bluetoothAvailableDevices', this.availableDevices);
});
}
/**
* Subscribe bond state change
*/
private subscribeBondStateChange() {
BluetoothModel.subscribeBondStateChange((data: {
deviceId: string;
bondState: number;
}) => {
Logger.info(this.TAG + "data.bondState" + JSON.stringify(data.bondState))
//paired devices
if (data.bondState !== BondState.BOND_STATE_BONDING) {
AppStorage.SetOrCreate("controlPairing", true)
this.refreshPairedDevices();
}
//available devices
if (data.bondState == BondState.BOND_STATE_BONDING) {
AppStorage.SetOrCreate("controlPairing", false)
// case bonding
// do nothing and still listening
Logger.info(this.TAG + 'bluetooth continue listening bondStateChange.');
if (this.getAvailableDevice(data.deviceId) != null) {
this.getAvailableDevice(data.deviceId).connectionState = ProfileConnectionState.STATE_CONNECTING;
}
} else if (data.bondState == BondState.BOND_STATE_INVALID) {
AppStorage.SetOrCreate("controlPairing", true)
// case failed
if (this.getAvailableDevice(data.deviceId) != null) {
this.getAvailableDevice(data.deviceId).connectionState = ProfileConnectionState.STATE_DISCONNECTED;
}
this.forceRefresh(this.availableDevices);
AppStorage.SetOrCreate('bluetoothAvailableDevices', this.availableDevices);
let showFlag = AppStorage.Get('BluetoothFailedDialogFlag');
if (showFlag == false) {
AppStorage.SetOrCreate('BluetoothFailedDialogFlag', true);
return;
}
} else if (data.bondState == BondState.BOND_STATE_BONDED) {
// case success
Logger.info(this.TAG + 'bluetooth bonded : remove device.');
this.removeAvailableDevice(data.deviceId);
BluetoothModel.connectDevice(data.deviceId);
}
});
}
/**
* Subscribe device connect state change
*/
private subscribeDeviceConnectStateChange() {
BluetoothModel.subscribeDeviceStateChange((data: {
profileId: number;
deviceId: string;
profileConnectionState: number;
}) => {
Logger.info(this.TAG + 'device connection state changed. profileId:' + JSON.stringify(data.profileId)
+ ' profileConnectionState: ' + JSON.stringify(data.profileConnectionState));
for (let device of this.pairedDevices) {
if (device.deviceId === data.deviceId) {
device.setProfile(data);
this.sortPairedDevices();
AppStorage.SetOrCreate('bluetoothPairedDevices', this.pairedDevices);
break;
}
};
Logger.info(this.TAG + 'device connection state changed. pairedDevices length = '
+ JSON.stringify(this.pairedDevices.length))
Logger.info(this.TAG + 'device connection state changed. availableDevices length = '
+ JSON.stringify(this.availableDevices.length))
this.removeAvailableDevice(data.deviceId);
});
}
//---------------------- private ----------------------
/**
* Get device by device id.
* @param deviceId device id
*/
protected getDevice(deviceId: string): BluetoothDevice {
let device = new BluetoothDevice();
device.deviceId = deviceId;
device.deviceName = BluetoothModel.getDeviceName(deviceId);
device.deviceType = BluetoothModel.getDeviceType(deviceId);
device.setProfiles(BluetoothModel.getDeviceState(deviceId));
return device;
}
/**
* Force refresh array.
* Note: the purpose of this function is just trying to fix page (ets) level's bug below,
* and should be useless if fixed by the future sdk.
* Bug Details:
* @State is not supported well for Array<CustomClass> type.
* In the case that the array item's field value changed, while not its length,
* the build method on page will not be triggered!
*/
protected forceRefresh(arr: BluetoothDevice[]): void {
arr.push(new BluetoothDevice())
arr.pop();
}
/**
* Start bluetooth discovery.
*/
public startBluetoothDiscovery() {
this.isDeviceDiscovering = true;
BluetoothModel.startBluetoothDiscovery();
this.discoveryStopTimeoutId = setTimeout(() => {
this.stopBluetoothDiscovery();
}, DISCOVERY_DURING_TIME);
}
/**
* Stop bluetooth discovery.
*/
private stopBluetoothDiscovery() {
this.isDeviceDiscovering = false;
BluetoothModel.stopBluetoothDiscovery();
this.discoveryStartTimeoutId = setTimeout(() => {
this.startBluetoothDiscovery();
}, DISCOVERY_INTERVAL_TIME);
}
/**
* Stop bluetooth discovery.
*/
private mStopBluetoothDiscovery() {
this.isDeviceDiscovering = false;
BluetoothModel.stopBluetoothDiscovery();
if (this.discoveryStartTimeoutId) {
clearTimeout(this.discoveryStartTimeoutId);
}
if (this.discoveryStopTimeoutId) {
clearTimeout(this.discoveryStopTimeoutId);
}
}
/**
* Get available device.
*
* @param deviceId device id
*/
private getAvailableDevice(deviceIds: string): BluetoothDevice {
Logger.info(this.TAG + 'getAvailableDevice length = ' + this.availableDevices.length);
let temp = this.availableDevices;
for (let i = 0; i < temp.length; i++) {
if (temp[i].deviceId === deviceIds) {
return temp[i];
}
}
return null;
}
/**
* Remove available device.
*
* @param deviceId device id
*/
private removeAvailableDevice(deviceId: string): void {
Logger.info(this.TAG + 'removeAvailableDevice : before : availableDevices length = ' + this.availableDevices.length);
this.availableDevices = this.availableDevices.filter((device) => device.deviceId !== deviceId)
AppStorage.SetOrCreate('bluetoothAvailableDevices', this.availableDevices);
Logger.info(this.TAG + 'removeAvailableDevice : after : availableDevices length = ' + this.availableDevices.length);
}
}

View File

@ -1,74 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import worker, { MessageEvents } from '@ohos.worker';
const TAG = 'EntryAbility'
enum fileOperateType {
WRITE = 0,
READ = 1
}
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
globalThis.context = this.context;
globalThis.pathDir = this.context.filesDir;
globalThis.nfc = 0;
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
AppStorage.setOrCreate("writeTimeSpeed",0);
AppStorage.setOrCreate("readTimeSpeed",0);
AppStorage.setOrCreate("btnEnable",true);
let AtManager = abilityAccessCtrl.createAtManager();
AtManager.requestPermissionsFromUser(this.context, ['ohos.permission.READ_MEDIA', 'ohos.permission.WRITE_MEDIA',
'ohos.permission.CAPTURE_SCREEN', 'ohos.permission.INTERNET', 'ohos.permission.CAMERA',
'ohos.permission.MICROPHONE', 'ohos.permission.START_INVISIBLE_ABILITY']).then(() => {
});
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground() {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground() {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}

View File

@ -1,90 +0,0 @@
/**
* 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 { ProfileConnectionState } from './BluetoothModel';
export class Profile {
profileId: number = -1;
profileConnectionState: number = -1
constructor() {
}
}
/**
* Bluetooth device class
*/
export default class BluetoothDevice {
deviceId: string = '';
deviceName: string = '';
deviceType: string = '';
connectionState: number = 0;
profiles: Map<number, Profile> = new Map();
constructor() {
}
setProfiles(data: Array<{
profileId: number;
profileConnectionState: number;
}>): void{
data.forEach((item: {
profileId: number;
profileConnectionState: number;
}) => {
this.setProfile({
profileId: item.profileId,
deviceId: this.deviceId,
profileConnectionState: item.profileConnectionState
})
})
}
setProfile(data: {
profileId: number;
deviceId: string;
profileConnectionState: number;
}): void{
if (this.deviceId !== data.deviceId) {
return;
}
this.profiles.set(data.profileId, data)
let countStateDisconnect = 0;
let countStateConnecting = 0;
let countStateConnected = 0;
let countStateDisconnecting = 0;
this.profiles.forEach((profile, key) => {
if (profile.profileConnectionState == ProfileConnectionState.STATE_DISCONNECTED) {
countStateDisconnect++;
} else if (profile.profileConnectionState == ProfileConnectionState.STATE_CONNECTING) {
countStateConnecting++;
} else if (profile.profileConnectionState == ProfileConnectionState.STATE_CONNECTED) {
countStateConnected++;
} else if (profile.profileConnectionState == ProfileConnectionState.STATE_DISCONNECTING) {
countStateDisconnecting++;
}
});
if (countStateConnected > 0 || countStateDisconnecting > 0) {
this.connectionState = ProfileConnectionState.STATE_CONNECTED;
} else if (countStateConnecting > 0) {
this.connectionState = ProfileConnectionState.STATE_CONNECTING;
} else {
this.connectionState = ProfileConnectionState.STATE_DISCONNECTED;
}
}
}

View File

@ -1,566 +0,0 @@
/**
* 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 bluetooth from '@ohos.bluetooth';
import bluetoothManager from '@ohos.bluetoothManager';
import Logger from './Logger'
export enum ProfileCode {
CODE_BT_PROFILE_A2DP_SINK = 0,
CODE_BT_PROFILE_A2DP_SOURCE,
CODE_BT_PROFILE_AVRCP_CT,
CODE_BT_PROFILE_AVRCP_TG,
CODE_BT_PROFILE_HANDS_FREE_AUDIO_GATEWAY,
CODE_BT_PROFILE_HANDS_FREE_UNIT,
CODE_BT_PROFILE_HID_HOST,
CODE_BT_PROFILE_PAN_NETWORK,
CODE_BT_PROFILE_PBAP_CLIENT,
CODE_BT_PROFILE_PBAP_SERVER,
};
export enum ProfileConnectionState {
/** the current profile is disconnected */
STATE_DISCONNECTED = 0,
/** the current profile is being connected */
STATE_CONNECTING = 1,
/** the current profile is connected */
STATE_CONNECTED = 2,
/** the current profile is being disconnected */
STATE_DISCONNECTING = 3
}
export enum BondState {
/** Indicate the bond state is invalid */
BOND_STATE_INVALID = 0,
/** Indicate the bond state is bonding */
BOND_STATE_BONDING = 1,
/** Indicate the bond state is bonded*/
BOND_STATE_BONDED = 2
}
export enum DeviceType {
BLUETOOTH = '1',
HEADPHONE = '2',
PHONE = '3',
COMPUTER = '4',
WATCH = '5'
}
export enum BluetoothErrorCode {
SUCCESS = -1,
HOLD_PAIRING_MODE = 1,
APP_PAIR = 2,
PAIR_FAILED = 3,
DEVICE_ILLEGAL = 4,
CONNECT_FAILED = 5
}
enum BluetoothState {
/** Indicates the local Bluetooth is off */
STATE_OFF = 0,
/** Indicates the local Bluetooth is turning on */
STATE_TURNING_ON = 1,
/** Indicates the local Bluetooth is on, and ready for use */
STATE_ON = 2,
/** Indicates the local Bluetooth is turning off */
STATE_TURNING_OFF = 3,
/** Indicates the local Bluetooth is turning LE mode on */
STATE_BLE_TURNING_ON = 4,
/** Indicates the local Bluetooth is in LE only mode */
STATE_BLE_ON = 5,
/** Indicates the local Bluetooth is turning off LE only mode */
STATE_BLE_TURNING_OFF = 6
}
/**
* bluetooth service class
*/
export class BluetoothModel {
private TAG = 'BluetoothModel ';
private profiles: any[] = new Array(10);
public canUse: boolean = false;
/**
* constructor
*/
constructor() {
try{
Logger.info('bluetooth.getProfile start')
let ProfileId = bluetoothManager.ProfileId;
this.profiles[ProfileId.PROFILE_A2DP_SOURCE]
= bluetoothManager.getProfileInstance(ProfileId.PROFILE_A2DP_SOURCE);
this.profiles[ProfileId.PROFILE_HANDS_FREE_AUDIO_GATEWAY]
= bluetoothManager.getProfileInstance(ProfileId.PROFILE_HANDS_FREE_AUDIO_GATEWAY);
this.profiles[ProfileId.PROFILE_HID_HOST]
= bluetoothManager.getProfileInstance(ProfileId.PROFILE_HID_HOST);
Logger.info('bluetooth.getProfile end')
this.canUse = true;
}
catch(error){
Logger.info('bluetooth.getProfile error')
this.canUse = false;
Logger.info(`BluetoothModel error: ${JSON.stringify(error)}.`);
}
}
/**
* Get Bluetooth status
* @return value of bluetooth.BluetoothState type
*/
getState(): number {
let bluetoothState = bluetooth.getState();
Logger.info(`${this.TAG} getState: bluetoothState = ${bluetoothState}`);
return bluetoothState;
}
/**
* Get Bluetooth switch status
*/
isStateOn(): boolean {
let result = false;
let state = bluetooth.getState();
Logger.info(`${this.TAG} isStateOn: state = ${state}`);
switch (state) {
case BluetoothState.STATE_ON:
result = true
break;
default:
break;
}
Logger.info(`${this.TAG} isStateOn: bluetoothState = ${result}`);
return result;
}
/**
* Subscribe Bluetooth switch status Change
*/
subscribeStateChange(callback: (data: boolean) => void): void {
Logger.info('bluetooth.subscribeStateChange start');
bluetooth.on('stateChange', (data) => {
Logger.info(`${this.TAG} subscribeStateChange->stateChange data:${data}`);
if (callback) {
switch (data) {
case BluetoothState.STATE_ON:
bluetooth.setBluetoothScanMode(4, 0);
Logger.info(`${this.TAG} subscribeStateChange->stateChange return: true`);
callback(true)
break;
case BluetoothState.STATE_OFF:
Logger.info(`${this.TAG} subscribeStateChange->stateChange return: false`);
callback(false)
break;
default:
break;
}
}
})
}
/**
* unsubscribe Bluetooth switch status Change
*/
unsubscribeStateChange(callback?: (data: boolean) => void): void {
Logger.info('bluetooth.unsubscribeStateChange start');
bluetooth.off('stateChange', (data) => {
Logger.info(`${this.TAG} unsubscribeStateChange->stateChange data:${data}`);
if (callback) {
let result = false;
switch (data) {
case BluetoothState.STATE_ON:
Logger.info(`${this.TAG} unsubscribeStateChange->stateChange return : true`);
callback(true)
break;
case BluetoothState.STATE_OFF:
Logger.info(`${this.TAG} unsubscribeStateChange->stateChange return : false`);
callback(false)
break;
default:
break;
}
}
})
}
/**
* Turn on Bluetooth
*/
enableBluetooth(): boolean {
return bluetooth.enableBluetooth();
}
/**
* Turn off Bluetooth
*/
disableBluetooth(): boolean {
return bluetooth.disableBluetooth();
}
/**
* Get local name
*/
getLocalName(): string {
return bluetooth.getLocalName();
}
/**
* Set local name
*/
setLocalName(name: string): boolean {
return bluetooth.setLocalName(name);
}
/**
* Get paired device ids
*/
getPairedDeviceIds(): Array<string> {
return bluetooth.getPairedDevices();
}
/**
* Start Bluetooth discovery
*/
startBluetoothDiscovery(): boolean {
return bluetooth.startBluetoothDiscovery();
}
/**
* Stop Bluetooth discovery
*/
stopBluetoothDiscovery(): boolean {
return bluetooth.stopBluetoothDiscovery();
}
/**
* Subscribe Bluetooth status Change
*/
subscribeBluetoothDeviceFind(callback: (data: Array<string>) => void): void {
Logger.info('bluetooth.subscribeBluetoothDeviceFind start');
bluetooth.on('bluetoothDeviceFind', (data: Array<string>) => {
Logger.info(`${this.TAG} subscribeBluetoothDeviceFind->deviceFind callback`);
if (callback) {
callback(data)
}
})
}
/**
* unsubscribe Bluetooth status Change
*/
unsubscribeBluetoothDeviceFind(callback?: (data: Array<string>) => void): void {
Logger.info('bluetooth.unsubscribeBluetoothDeviceFind start');
bluetooth.off('bluetoothDeviceFind', (data) => {
Logger.info(`${this.TAG} unsubscribeBluetoothDeviceFind->deviceFind callback`);
if (callback) {
callback(data)
}
})
}
/**
* Pair device
*/
pairDevice(deviceId: string): boolean {
return bluetooth.pairDevice(deviceId);
}
/**
* Subscribe PinRequired
*/
subscribePinRequired(callback: (data: {
deviceId: string;
pinCode: string;
}) => void): void {
Logger.info('bluetooth.subscribePinRequired start');
bluetooth.on('pinRequired', (data: {
deviceId: string;
pinCode: string;
}) => {
Logger.info(`${this.TAG} subscribePinRequired->pinRequired return: ${data.pinCode}`);
if (callback) {
callback(data)
}
})
}
/**
* Unsubscribe PinRequired
*/
unsubscribePinRequired(callback?: (data: {
deviceId: string;
pinCode: string;
}) => void): void {
Logger.info('bluetooth.unsubscribePinRequired start');
bluetooth.off('pinRequired', (data: {
deviceId: string;
pinCode: string;
}) => {
if(data == undefined || !data){
Logger.error(`${this.TAG} unsubscribePinRequired->pinRequired error`);
return;
}
Logger.info(`${this.TAG} unsubscribePinRequired->pinRequired return: ${data.pinCode}`);
if (callback) {
callback(data)
}
})
}
/**
* Set device PairingConfirmation
*/
setDevicePairingConfirmation(deviceId: string, accept: boolean): boolean {
Logger.info('bluetooth.setDevicePairingConfirmation start, accept:' + accept);
let ret = bluetooth.setDevicePairingConfirmation(deviceId, accept);
Logger.info('bluetooth.unsubscribePinRequired end, ret: ' + ret);
return ret;
}
/**
* Subscribe bondStateChange
*/
subscribeBondStateChange(callback): void {
Logger.info('bluetooth.subscribeBondStateChange start');
bluetooth.on('bondStateChange', (data) => {
Logger.info(`${this.TAG} subscribeBondStateChange->bondStateChange data.state:${JSON.stringify(data.state)}`);
if (callback) {
let result = {
deviceId: data.deviceId,
bondState: data.state
}
Logger.info(`${this.TAG} subscribeBondStateChange->bondStateChange return:${JSON.stringify(result.bondState)}`);
callback(result);
}
})
}
/**
* Unsubscribe bondStateChange
*/
unsubscribeBondStateChange(callback?: (data: {
deviceId: string;
bondState: number;
}) => void): void {
bluetooth.off('bondStateChange', (data) => {
Logger.info(`${this.TAG} unsubscribeBondStateChange->bondStateChange start`);
if (callback) {
let result = {
deviceId: data.deviceId,
bondState: data.state
}
Logger.info(`${this.TAG} unsubscribeBondStateChange->bondStateChange return:${JSON.stringify(result.bondState)}`);
callback(result);
}
})
}
/**
* Get device name
*/
getDeviceName(deviceId: string): string {
return bluetooth.getRemoteDeviceName(deviceId);
}
/**
* Get device type
*/
getDeviceType(deviceId: string): string {
let deviceType = DeviceType.BLUETOOTH;
let deviceClass = bluetooth.getRemoteDeviceClass(deviceId);
switch (deviceClass.majorClass) {
case 0x0100:
deviceType = DeviceType.COMPUTER;
break;
case 0x0400:
if (deviceClass.majorMinorClass === 0x0418 || deviceClass.majorMinorClass === 0x0404) {
deviceType = DeviceType.HEADPHONE;
}
break;
case 0x0700:
if (deviceClass.majorMinorClass === 0x0704) {
deviceType = DeviceType.WATCH;
}
break;
case 0x0200:
deviceType = DeviceType.PHONE;
break;
default:
deviceType = DeviceType.BLUETOOTH;
break;
}
Logger.info('bluetooth.getDeviceType end, return:' + deviceType);
return deviceType;
}
/**
* Get device state
*/
getDeviceState(deviceId: string): Array<{
profileId: number;
profileConnectionState: number;
}> {
let result = [];
for (let i = 0;i < this.profiles.length; i++) {
if (this.profiles[i]) {
try {
let state = this.profiles[i].getDeviceState(deviceId);
result.push({
profileId: i,
profileConnectionState: state
});
} catch (BusinessError) {
Logger.error("Bluetooth getDeviceState failed , BusinessError is " + JSON.stringify(BusinessError))
}
}
}
return result;
}
/**
* Unpair device
*/
unpairDevice(deviceId: string): boolean {
return bluetooth.cancelPairedDevice(deviceId);
}
/**
* Connect device
*/
connectDevice(deviceId: string): Array<{
profileId: number;
connectRet: boolean;
}> {
Logger.info('bluetooth.connectDevice start');
let result = [];
for (let i = 0;i < this.profiles.length; i++) {
if (this.profiles[i]) {
let profile = this.profiles[i];
let connectRet = true;
try {
profile.connect(deviceId);
} catch (BusinessError) {
Logger.info(`${this.TAG} connect failed. BusinessError is ` + JSON.stringify(BusinessError));
connectRet = false;
}
result.push({
profileId: i,
connectRet: connectRet
});
}
}
Logger.info('bluetooth.connectDevice end, return:' + result);
return result;
}
/**
* Disconnect device
*/
disconnectDevice(deviceId: string): Array<{
profileId: number;
disconnectRet: boolean;
}> {
Logger.info('bluetooth.disconnectDevice start');
let result = [];
for (let i = 0;i < this.profiles.length; i++) {
let profile = this.profiles[i];
if (this.profiles[i]) {
let profileConnectionState = profile.getDeviceState(deviceId);
let disconnectRet = true;
Logger.info(`${this.TAG} disconnectDevice , connectionState = ${profileConnectionState}`);
if (profileConnectionState === 2) {
try {
profile.disconnect(deviceId);
} catch (BusinessError) {
Logger.info(`${this.TAG} disconnect failed. BusinessError is ` + JSON.stringify(BusinessError));
disconnectRet = false;
}
}
result.push({
profileId: i,
disconnectRet: disconnectRet
});
}
}
Logger.info('bluetooth.connectDevice end, return:' + result);
return result;
}
/**
* Subscribe device connection state Change
*/
subscribeDeviceStateChange(callback: (data: {
profileId: number;
deviceId: string;
profileConnectionState: number;
}) => void): void {
for (let i = 0;i < this.profiles.length; i++) {
if (this.profiles[i]) {
let profile = this.profiles[i];
profile.on('connectionStateChange', (data) => {
if (callback) {
let result = {
profileId: i,
deviceId: data.deviceId,
profileConnectionState: data.state
};
Logger.info(`${this.TAG} subscribeDeviceStateChange->connectionStateChange,
return:${result.profileId} - ${result.profileConnectionState}`);
callback(result);
}
})
}
}
}
/**
* unsubscribe device connection state Change
*/
unsubscribeDeviceStateChange(callback?: (data: {
profileId: number;
deviceId: string;
profileConnectionState: number;
}) => void): void {
for (let i = 0;i < this.profiles.length; i++) {
if (this.profiles[i]) {
let profile = this.profiles[i];
profile.off('connectionStateChange', (data) => {
if(data == undefined || !data){
Logger.error(`${this.TAG} unsubscribeDeviceStateChange->connectionStateChange error`);
return;
}
if (callback) {
let result = {
profileId: i,
deviceId: data.deviceId,
profileConnectionState: data.state
};
Logger.info(`${this.TAG} unsubscribeDeviceStateChange->connectionStateChange,
return:${result.profileId} - ${result.profileConnectionState}`);
callback(result);
}
})
}
}
}
}
let bluetoothModel = new BluetoothModel();
export default bluetoothModel as BluetoothModel;

View File

@ -1,98 +0,0 @@
/*
* 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.
*/
/**
* @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)}`
}
getDurationString(duration: number) {
let hour = Math.floor(duration / (1000 * 60 * 60))
let minute = Math.floor((duration - hour * (1000 * 60 * 60)) / (1000 * 60))
let second = Math.floor((duration - hour * (1000 * 60 * 60) - minute * (60 * 1000)) / 1000)
if (hour > 0) {
return `${this.fill(hour)}:${this.fill(minute)}:${this.fill(second)}`
}
return `${this.fill(minute)}:${this.fill(second)}`
}
}

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class Logger {
private prefix: string
constructor(prefix: string) {
this.prefix = prefix
}
log(...args: string[]) {
console.log(`[${this.prefix}].${args.join(' ')}`)
}
info(...args: string[]) {
console.log(`[${this.prefix}].${args.join(' ')}`)
}
debug(...args: string[]) {
console.log(`[${this.prefix}].${args.join(' ')}`)
}
error(...args: string[]) {
console.log(`[${this.prefix}].${args.join(' ')}`)
}
}
export default new Logger('[Sample_Wlan]')

View File

@ -1,44 +0,0 @@
/*
* 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 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('[Factory]');

View File

@ -1,41 +0,0 @@
/*
* 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.
*/
export function getTimeString(timeIndex: number, index: number) {
let result = timeIndex + index - 3
if (result < 0) {
return ' '
}
if (result % 60 < 10) {
return '0' + Math.floor(result / 60) + ':0' + (result % 60)
}
if (result % 60 >= 10) {
return '0' + Math.floor(result / 60) + ':' + (result % 60)
}
}
export function updateTime(millisecond: number) {
let minute = parseInt((millisecond / 60000).toString())
let second = parseInt(((millisecond - (minute * 60000)) / 1000).toString())
let minuteStr = '' + minute
let secondStr = '' + second
if (minute < 10) {
minuteStr = "0" + minute
}
if (second < 10) {
secondStr = "0" + second
}
return minuteStr + ':' + secondStr;
}

View File

@ -1,128 +0,0 @@
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import prompt from '@ohos.promptAction'
import wifi from '@ohos.wifiManager'
import Logger from './Logger'
const TAG: string = 'WiFiModel'
export type WifiType = {
ssid: string,
bssid: string,
securityType: wifi.WifiSecurityType,
rssi: number,
band: number,
frequency: number,
timestamp: number
}
export class WifiModel {
async getScanInfos(): Promise<Array<WifiType>> {
Logger.info(TAG, 'scanWifi begin')
let wifiList: Array<WifiType> = []
let result: Array<wifi.WifiScanInfo> = []
try {
result = await wifi.getScanResults()
} catch (err) {
Logger.info(TAG, `scan info err: ${JSON.stringify(err)}`)
return wifiList
}
Logger.info(TAG, `scan info call back: ${result.length}`)
for (var i = 0; i < result.length; ++i) {
wifiList.push({
ssid: result[i].ssid,
bssid: result[i].bssid,
securityType: result[i].securityType,
rssi: result[i].rssi,
band: result[i].band,
frequency: result[i].frequency,
timestamp: result[i].timestamp
})
}
return wifiList
}
connectNetwork(scanInfo: wifi.WifiScanInfo, psw) {
prompt.showToast({ message: 'connecting', duration: 5000 })
Logger.debug(TAG, `connectNetwork bssid=${scanInfo.bssid}`)
// 这里因为api问题需要声明为any已提单
let deviceConfig: any = {
ssid: scanInfo.ssid,
bssid: scanInfo.bssid,
preSharedKey: psw,
isHiddenSsid: false,
securityType: scanInfo.securityType
}
try {
wifi.connectToDevice(deviceConfig)
Logger.debug(TAG, `connectToDevice success`)
} catch (err) {
Logger.debug(TAG, `connectToDevice fail err is ${JSON.stringify(err)}`)
}
try {
wifi.addDeviceConfig(deviceConfig)
} catch (err) {
Logger.debug(TAG, `addDeviceConfig fail err is ${JSON.stringify(err)}`)
}
}
resolveIP(ip) {
let address: string = ip.toString()
if (address === '0') {
return '00:00:000:000'
}
address.substring(0, 2)
return `${address.substring(0, 2)}:${address.substring(2, 4)}:${address.substring(4, 7)}:${address.substring(7, 10)}`
}
getIpInfo() {
let ipInfoList = []
let ipInfo = wifi.getIpInfo()
Logger.info(`${TAG} getIpInfo=${JSON.stringify(ipInfo)}`)
ipInfoList.push({ key: $r('app.string.ip_address'), value: this.resolveIP(ipInfo.ipAddress) })
ipInfoList.push({ key: $r('app.string.gate_way'), value: this.resolveIP(ipInfo.gateway) })
ipInfoList.push({ key: $r('app.string.net_mask'), value: this.resolveIP(ipInfo.netmask) })
ipInfoList.push({ key: $r('app.string.primary_dns'), value: this.resolveIP(ipInfo.primaryDns) })
ipInfoList.push({ key: $r('app.string.second_dns'), value: this.resolveIP(ipInfo.secondDns) })
ipInfoList.push({ key: $r('app.string.server_ip'), value: this.resolveIP(ipInfo.serverIp) })
ipInfoList.push({ key: $r('app.string.lease_duration'), value: ipInfo.leaseDuration.toString() })
return ipInfoList
}
getCountryCode() {
let countryCodeList = []
let countryCode = wifi.getCountryCode()
countryCodeList.push({ key: $r('app.string.country_code'), value: countryCode })
return countryCodeList
}
getFeatureSupport() {
let featureSupportedList = []
featureSupportedList.push({
key: $r('app.string.infrastructure_feature'),
value: wifi.isFeatureSupported(0x0001).toString()
})
featureSupportedList.push({ key: $r('app.string.ghz_feature'), value: wifi.isFeatureSupported(0x0002).toString() })
featureSupportedList.push({
key: $r('app.string.gas_anqp_feature'),
value: wifi.isFeatureSupported(0x0004).toString()
})
featureSupportedList.push({ key: $r('app.string.wifi_direct'), value: wifi.isFeatureSupported(0x0008).toString() })
featureSupportedList.push({ key: $r('app.string.soft_ap'), value: wifi.isFeatureSupported(0x0010).toString() })
featureSupportedList.push({ key: $r('app.string.wifi_aware'), value: wifi.isFeatureSupported(0x0040).toString() })
return featureSupportedList
}
}

View File

@ -1,60 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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 deviceInfo from '@ohos.deviceInfo'
import statvfs from '@ohos.file.statvfs'
import systemparameter from '@ohos.systemParameterEnhance'
// @ts-ignore
import deviceinfonapi from '@ohos.deviceinfonapi'
export class deviceInfos {
public osFullName; // 系统版本
public sdkApiVersion; // 系统软件API版本
public deviceType; // 设备类型
public cpuFrequency; // cpu频率
public cpuModule; // cpu型号
public memCapacity; // 内存容量
public stoCapacity; // 存储容量
public usedCapacity; // 已使用存储容量
public freeCapacity; // 剩余容量
public manufacture;// 设备厂家名称
public marketName;// 外部产品系列
public productSeries;// 产品系列
constructor() {
}
bytesToMB(bytes) { return bytes / (1024 * 1024);}
async init(){
this.osFullName = deviceInfo.osFullName;
this.sdkApiVersion = await systemparameter.get('const.ohos.apiversion');
this.deviceType = deviceInfo.deviceType;
this.cpuFrequency = (await deviceinfonapi.get_cpu_frequency()/1000).toFixed(0).toString()+ 'MHZ';
this.cpuModule = await systemparameter.get('const.product.cpu.abilist');
// 内存容量
this.memCapacity = this.bytesToMB(await deviceinfonapi.get_mem_capacity()).toFixed(0) + 'M';
let filesDir = globalThis.context.filesDir;
// 存储容量
let stoCapacityBite = await statvfs.getTotalSize(filesDir);
this.stoCapacity = this.bytesToMB(stoCapacityBite).toFixed(0) + 'M';
// 剩余容量
let freeCapacityBite = await statvfs.getFreeSize(filesDir);
this.freeCapacity = this.bytesToMB(freeCapacityBite).toFixed(0) + 'M';
this.usedCapacity = this.bytesToMB(stoCapacityBite - freeCapacityBite).toFixed(0) + 'M';
this.manufacture = deviceInfo.manufacture;
this.marketName = deviceInfo.marketName;
this.productSeries = deviceInfo.productSeries;
}
}

View File

@ -1,451 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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
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 './MediaUtils'
import ThumbnailGetter from './ThumbnailGetter'
const CameraSize = {
WIDTH: 1280,
HEIGHT: 720
}
const TAG = 'CameraService'
class CameraService {
private static instance: CameraService = new CameraService()
private mediaUtil = MediaUtils.getInstance()
private cameraManager: camera.CameraManager = undefined
cameras: Array<camera.CameraDevice> = undefined
private cameraInput: camera.CameraInput = undefined
private previewOutput: camera.PreviewOutput = undefined
private photoOutput: camera.PhotoOutput = undefined
private cameraOutputCapability: camera.CameraOutputCapability = undefined
private captureSession: camera.CaptureSession = undefined
private mReceiver: image.ImageReceiver = undefined
private videoPrepareFile: mediaLibrary.FileAsset = undefined
private mFileAssetId = 0
private avRecorder: media.AVRecorder = undefined
private videoOutput: camera.VideoOutput = undefined
private mThumbnailGetter = new ThumbnailGetter()
private handleTakePicture: (photoUri: string) => void = undefined
private videoConfig: any = {
audioSourceType: 1,
videoSourceType: 1,
profile: {
audioBitrate: 48000,
audioChannels: 1,
audioCodec: 'audio/mp4a-latm',
audioSampleRate: 48000,
fileFormat: 'mp4',
videoBitrate: 280000,
videoCodec: 'video/avc',
videoFrameWidth: 640,
videoFrameHeight: 480,
videoFrameRate: 30,
},
rotation: 0,
url: '',
orientationHint: 0,
location: { latitude: 30, longitude: 130 },
}
private videoProfileObj: camera.VideoProfile = {
format: 1,
size: {
"width": 640,
"height": 480
},
frameRateRange: {
"min": 5,
"max": 5
}
}
private photoProfileObj: camera.Profile = {
format: 1,
size: {
"width": 640,
"height": 480
}
}
private videoOutputStopBol: boolean = true
resolution: any = null
photoResolution: any = null
videoResolution: any = null
constructor() {
try {
this.mReceiver = image.createImageReceiver(CameraSize.WIDTH, CameraSize.HEIGHT, image.ImageFormat.JPEG, 8)
Logger.info(TAG, 'createImageReceiver')
this.mReceiver.on('imageArrival', () => {
Logger.info(TAG, 'imageArrival')
this.mReceiver.readNextImage((err, image) => {
Logger.info(TAG, 'readNextImage')
if (err || image === undefined) {
Logger.error(TAG, 'failed to get valid image')
return
}
image.getComponent(4, (errMsg, img) => {
Logger.info(TAG, 'getComponent')
if (errMsg || img === undefined) {
Logger.info(TAG, 'failed to get valid buffer')
return
}
let buffer
if (img.byteBuffer) {
buffer = img.byteBuffer
} else {
Logger.error(TAG, 'img.byteBuffer is undefined')
}
this.savePicture(buffer, image)
})
})
})
} catch (err) {
Logger.info(TAG, `image Receiver err ${err.message}`)
}
}
async savePicture(buffer: ArrayBuffer, img: image.Image) {
try {
Logger.info(TAG, 'savePicture')
let imgFileAsset = await this.mediaUtil.createAndGetUri(mediaLibrary.MediaType.IMAGE)
let imgPhotoUri = imgFileAsset.uri
Logger.info(TAG, `photoUri = ${imgPhotoUri}`)
let imgFd = await this.mediaUtil.getFdPath(imgFileAsset)
Logger.info(TAG, `fd = ${imgFd}`)
await fileio.write(imgFd, buffer)
await imgFileAsset.close(imgFd)
await img.release()
Logger.info(TAG, 'save image done')
if (this.handleTakePicture) {
this.handleTakePicture(imgPhotoUri)
}
} catch (err) {
Logger.info(TAG, `save picture err ${err.message}`)
}
}
public async createVideoFd(): Promise<number> {
Logger.info(TAG, `getVideoFd E`)
try {
let dataUri = await this.mediaUtil.createAndGetUri(mediaLibrary.MediaType.VIDEO)
this.videoPrepareFile = await this.mediaUtil.queryFile(dataUri);
const fdNumber = await this.videoPrepareFile.open('Rw')
return fdNumber;
} catch (err) {
Logger.error(TAG, `createVideoFd err: ` + err)
}
Logger.info(TAG, `getVideoFd X`)
}
async initCamera(surfaceId: number, cameraDeviceIndex: number, obj?, photoIndex?, previewObj?) {
try {
if (deviceInfo.deviceType === 'default') {
this.videoConfig.videoSourceType = 1
} else {
this.videoConfig.videoSourceType = 1
}
Logger.info(TAG, `cameraDeviceIndex success: ${cameraDeviceIndex}`)
await this.releaseCamera()
await this.getCameraManagerFn()
await this.getSupportedCamerasFn()
await this.getSupportedOutputCapabilityFn(cameraDeviceIndex)
if (previewObj) {
previewObj.format = this.cameraOutputCapability.previewProfiles[0].format
Logger.info(TAG, `previewObj format: ${previewObj.format}`)
}
await this.createPreviewOutputFn(previewObj ? previewObj : this.cameraOutputCapability.previewProfiles[0], surfaceId)
await this.createPhotoOutputFn(obj ? obj : this.cameraOutputCapability.photoProfiles[photoIndex?photoIndex:0])
await this.createCameraInputFn(this.cameras[cameraDeviceIndex])
await this.cameraInputOpenFn()
await this.sessionFlowFn()
} catch (err) {
Logger.info(TAG, 'initCamera err: ' + JSON.stringify(err.message))
}
}
setTakePictureCallback(callback) {
this.handleTakePicture = callback
}
// 拍照
async takePicture(imageRotation?) {
try {
Logger.info(TAG, 'takePicture start')
let photoSettings = {
rotation: imageRotation ? Number(imageRotation) : 0,
quality: 1,
location: {
latitude: 0,
longitude: 0,
altitude: 0
},
mirror: false
}
Logger.info(TAG, `photoOutput capture photoSettings: ` + JSON.stringify(photoSettings))
await this.photoOutput.capture(photoSettings)
Logger.info(TAG, 'takePicture end')
} catch (err) {
Logger.info(TAG, `takePicture fail err: ${err}, message: ${err.message}, code: ${err.code}`)
}
}
public async createVideoOutput() {
Logger.info(TAG, `createVideoOutput start`)
Logger.info(TAG, `createVideoOutput saveCameraAsset: ${this.mSaveCameraAsset}`)
this.mFileAssetId = await this.createVideoFd()
this.videoConfig.url = `fd://${this.mFileAssetId.toString()}`
await media.createAVRecorder().then((recorder) => {
Logger.info(TAG, `createVideoOutput createAVRecorder record: ${recorder}`)
this.avRecorder = recorder
})
if (this.avRecorder != null) {
this.avRecorder.on('error', (error) => {
if (error) {
Logger.error(TAG, `createVideoOutput error: ${JSON.stringify(error)}`)
}
})
Logger.info(TAG, `createVideoOutput size = ${JSON.stringify(this.cameraOutputCapability.videoProfiles[0].size)}`)
this.videoConfig.profile.videoFrameWidth = this.cameraOutputCapability.videoProfiles[0].size.width
this.videoConfig.profile.videoFrameHeight = this.cameraOutputCapability.videoProfiles[0].size.height
Logger.info(TAG, `createVideoOutput videoConfig: ` + JSON.stringify(this.videoConfig))
await this.avRecorder.prepare(this.videoConfig)
Logger.info(TAG, `createVideoOutput AVRecorder.prepare succeed.`)
} else {
Logger.error(TAG, `createVideoOutput createAVRecorder failed.`)
return
}
const videoId = await this.avRecorder.getInputSurface()
Logger.info(`${this.TAG} createVideoOutput profileVideo = ${JSON.stringify(this.cameraOutputCapability.videoProfiles[0])}.`)
try {
this.videoOutput = this.cameraManager.createVideoOutput(this.cameraOutputCapability.videoProfiles[0], videoId)
} catch (error) {
Logger.error(TAG, `createVideoOutput failed: ${JSON.stringify(error)}`)
}
Logger.info(TAG, `createVideoOutput end`)
}
// 开始录制
async StartRecording() {
try {
Logger.info(TAG, `StartRecording begin`)
await this.captureSession.stop()
this.captureSession.beginConfig()
// if (this.videoOutput) {
// await this.captureSession.removeOutput(this.videoOutput)
// Logger.info(TAG, `old videoOutput has been removed.`)
// }
await this.createVideoOutput()
this.captureSession.addOutput(this.videoOutput)
Logger.info(TAG, `StartRecording addOutput finished.`)
await this.captureSession.commitConfig()
Logger.info(TAG, `StartRecording commitConfig finished.`)
await this.captureSession.start()
Logger.info(TAG, `StartRecording Session.start finished.`)
} catch (err) {
Logger.info(TAG, `remove videoOutput ${err}`)
}
await this.videoOutput.start().then(() => {
Logger.info(TAG, `videoOutput.start()`)
})
await this.avRecorder.start().then(() => {
Logger.info(TAG, `AVRecorder.start()`)
})
Logger.info(TAG, `StartRecording end`)
}
// 停止录制
async stopRecording() {
if (!this.videoOutput || !this.avRecorder) {
Logger.error(TAG, `stopRecording error videoOutPut: ${this.videoOutput},AVRecorder: ${this.avRecorder} .`)
return
}
try {
await this.avRecorder.stop()
await this.avRecorder.release()
} catch (err) {
Logger.error(TAG, `stop AVRecorder ${err}`)
}
try {
await this.videoOutput.stop()
} catch (err) {
Logger.error(TAG, `stop videoOutput ${err}`)
}
if (this.mFileAssetId != undefined) {
await this.videoPrepareFile.close(this.mFileAssetId)
this.mFileAssetId = undefined
Logger.info(TAG, `fileAsset.close().`)
}
const thumbnailPixelMap = await this.mThumbnailGetter.getThumbnailInfo(1280, 960)
Logger.info(TAG, `stopRecording invoke X.`)
return thumbnailPixelMap
}
// 查询相机设备在模式下支持的输出能力
async getSupportedOutputCapabilityFn(cameraDeviceIndex) {
Logger.info(TAG, `cameraOutputCapability cameraId: ${this.cameras[cameraDeviceIndex].cameraId}`)
// @ts-ignore
this.cameraOutputCapability = this.cameraManager.getSupportedOutputCapability(this.cameras[cameraDeviceIndex])
let previewSize = []
let photoSize = []
let videoSize = []
this.cameraOutputCapability.previewProfiles.forEach((item, index) => {
Logger.info(TAG, `cameraOutputCapability previewProfiles index: ${index}, item:` + JSON.stringify(item))
previewSize.push({
value: `${item.size.width}x${item.size.height}`
})
})
this.cameraOutputCapability.photoProfiles.forEach((item, index) => {
Logger.info(TAG, `cameraOutputCapability photoProfiles index: ${index}, item:` + JSON.stringify(item))
photoSize.push({
value: `${item.size.width}x${item.size.height}`
})
})
this.cameraOutputCapability.videoProfiles.forEach((item, index) => {
Logger.info(TAG, `cameraOutputCapability videoProfiles index: ${index}, item:` + JSON.stringify(item))
videoSize.push({
value: `${item.size.width}x${item.size.height}`
})
})
Logger.info(TAG, `cameraOutputCapability previewProfiles:` + JSON.stringify(this.cameraOutputCapability.previewProfiles))
Logger.info(TAG, `cameraOutputCapability photoProfiles:` + JSON.stringify(this.cameraOutputCapability.photoProfiles))
Logger.info(TAG, `cameraOutputCapability videoProfiles:` + JSON.stringify(this.cameraOutputCapability.videoProfiles))
Logger.info(TAG, `cameraOutputCapability previewProfiles previewSize:` + JSON.stringify(previewSize))
this.resolution = previewSize
this.photoResolution = photoSize
this.videoResolution = videoSize
return previewSize
}
// 释放会话及其相关参数
async releaseCamera() {
try {
if (this.cameraInput) {
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()
}
Logger.info(TAG, `releaseCamera success`)
} catch (err) {
Logger.info(TAG, `releaseCamera fail err: ${err}, message: ${err.message}, code: ${err.code}`)
}
}
// 释放会话
async releaseSession() {
await this.previewOutput.stop()
await this.photoOutput.release()
await this.captureSession.release()
Logger.info(TAG, `releaseSession success`)
}
// 获取相机管理器实例
async getCameraManagerFn() {
try {
this.cameraManager = await camera.getCameraManager(globalThis.context)
Logger.info(TAG, `getCameraManager success: ` + JSON.stringify(this.cameraManager))
} catch (err) {
Logger.info(TAG, `getCameraManagerFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
}
}
// 获取支持指定的相机设备对象
async getSupportedCamerasFn() {
try {
this.cameras = await this.cameraManager.getSupportedCameras()
Logger.info(TAG, `getSupportedCameras success: ` + JSON.stringify(this.cameras))
Logger.info(TAG, `getSupportedCameras length success: ${this.cameras.length}`)
} catch (err) {
Logger.info(TAG, `getSupportedCamerasFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
}
}
// 创建previewOutput输出对象
async createPreviewOutputFn(previewProfilesObj, surfaceId) {
try {
Logger.info(TAG, `createPreviewOutputFn previewProfilesObj success: ` + JSON.stringify(previewProfilesObj))
this.previewOutput = await this.cameraManager.createPreviewOutput(previewProfilesObj, surfaceId.toString())
Logger.info(TAG, `createPreviewOutputFn success: ` + JSON.stringify(this.previewOutput))
} catch (err) {
Logger.info(TAG, `createPreviewOutputFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
}
}
// 创建photoOutput输出对象
async createPhotoOutputFn(photoProfileObj) {
try {
Logger.info(TAG, `createPhotoOutputFn photoProfileObj success: ` + JSON.stringify(photoProfileObj))
let mSurfaceId = await this.mReceiver.getReceivingSurfaceId()
this.photoOutput = await this.cameraManager.createPhotoOutput(photoProfileObj, mSurfaceId)
Logger.info(TAG, `createPhotoOutputFn success: ` + JSON.stringify(this.photoOutput))
} catch (err) {
Logger.info(TAG, `createPhotoOutputFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
}
}
// 创建cameraInput输出对象
async createCameraInputFn(cameraDeviceIndex) {
try {
this.cameraInput = await this.cameraManager.createCameraInput(cameraDeviceIndex)
Logger.info(TAG, `createCameraInputFn success: ${this.cameraInput}`)
} catch (err) {
Logger.info(TAG, `createCameraInputFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
}
}
// 打开相机
async cameraInputOpenFn() {
await this.cameraInput.open()
.then((data) => {
Logger.info(TAG, `cameraInputOpenFn open success: ${data}`)
})
.catch((err) => {
Logger.info(TAG, `cameraInputOpenFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
})
}
// 会话流程
async sessionFlowFn() {
try {
// 创建captureSession实例
this.captureSession = await this.cameraManager.createCaptureSession()
// 开始配置会话
await this.captureSession.beginConfig()
// cameraInput加入会话
await this.captureSession.addInput(this.cameraInput)
// previewOutput加入会话
await this.captureSession.addOutput(this.previewOutput)
// photoOutput加入会话
await this.captureSession.addOutput(this.photoOutput)
// 提交配置会话
await this.captureSession.commitConfig()
// 开启会话
await this.captureSession.start()
Logger.info(TAG, `sessionFlowFn success`)
} catch (err) {
Logger.info(TAG, `sessionFlowFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
}
}
}
export default new CameraService()

View File

@ -1,177 +0,0 @@
/*
* Copyright 2023 Unionman Technology 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 Logger from '../../model/Logger'
import CameraService from './CameraService'
import FirstDialog from '../../common/FirstDialog'
import prompt from '@ohos.prompt'
import router from '@ohos.router'
const TAG = "Camera"
@Entry
@Component
struct Camera_index {
@State name: string = 'CameraVideo';
@State StepTips: string = '测试目的:用于测试相机录像分辨率能力\n预期结果所有分辨率均可以录像录像与预览一致';
private mXComponentController: XComponentController = new XComponentController()
@State surfaceId: number = 0;
@State cameraDeviceIndex: number = 0
@State assetUri: string = undefined
@State thumbnail: PixelMap = undefined
@State isTakePictureEnabled: boolean = true
@State isTakeVideoEnabled: boolean = true
@State clickFrequency: number = 0 // 点击次数
@State resolutionSelectVal: string = '' // 下拉框默认value
@State captureBtnScale: number = 1
async aboutToAppear() {
await FirstDialog.ChooseDialog(this.StepTips, this.name);
CameraService.setTakePictureCallback(this.handleTakePicture.bind(this))
Logger.info(TAG, `takePicture end, assetUri: ${this.assetUri}`)
}
async cameraInit(obj?) {
CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex).then(() => {
this.resolutionSelectVal = String(CameraService.videoResolution[this.clickFrequency].value)
Logger.info(TAG, `resolutionSelectVal ${this.resolutionSelectVal}`) //1280x960
})
}
handleTakePicture = (assetUri: string) => {
this.assetUri = assetUri
Logger.info(TAG, `takePicture end, assetUri: ${this.assetUri}`)
}
onPageShow() {
// @ts-ignore
this.surfaceId = this.mXComponentController.getXComponentSurfaceId()
CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex)
}
onPageHide() {
CameraService.releaseCamera()
Logger.info(TAG, `onPageHide releaseCamera end`)
}
build() {
Stack({ alignContent: Alignment.BottomEnd }) {
XComponent({
id: 'componentId',
type: 'surface',
controller: this.mXComponentController
})
.size({ width: '100%', height: '100%' })
.onLoad(async () => {
Logger.info(TAG, 'onLoad is called')
// @ts-ignore
this.surfaceId = this.mXComponentController.getXComponentSurfaceId()
Logger.info(TAG, `onLoad surfaceId: ${this.surfaceId}`)
this.cameraInit()
})
Row() {
if (this.assetUri !== undefined) {
Image(this.assetUri)
.size({ height: '100%' })
.border({ width: 1, color: Color.White, style: BorderStyle.Solid })
.onClick(async () => {
await globalThis.context.startAbility({
parameters: { uri: 'photodetail' },
bundleName: 'com.ohos.photos',
abilityName: 'com.ohos.photos.MainAbility'
})
})
}
Blank()
if (this.thumbnail !== undefined) {
Image(this.thumbnail)
.height('100%')
.aspectRatio(4 / 3)
.border({ width: 1, color: Color.White, style: BorderStyle.Solid })
.onClick(async () => {
await globalThis.context.startAbility({
parameters: { uri: 'photodetail' },
bundleName: 'com.ohos.photos',
abilityName: 'com.ohos.photos.MainAbility'
})
})
}
}.size({ width: '100%', height: '30%' }).justifyContent(FlexAlign.SpaceBetween)
Column() {
Image(this.isTakeVideoEnabled ? $r('app.media.take_video_normal') : $r('app.media.take_video_stop'))
.width(76).aspectRatio(1).enabled(this.isTakeVideoEnabled)
.onTouch((event: TouchEvent) => {
this.isTakeVideoEnabled = false
if (event.type === TouchType.Up) {
this.isTakeVideoEnabled = false
prompt.showToast({
message: '录制中,请等待三秒', duration: 1000
});
CameraService.StartRecording().then(() => {
setTimeout(() => {
CameraService.stopRecording().then((thumbnailPixelMap) => {
this.thumbnail = thumbnailPixelMap
this.isTakeVideoEnabled = true
})
}, 3000)
})
}
})
}.size({ height: '100%' }).justifyContent(FlexAlign.Center)
Row() {
Stack({ alignContent: Alignment.Center }) {
Image($r('app.media.ic_circled')).fillColor(Color.White)
Image($r('app.media.ic_circled_filled'))
.width(54)
.aspectRatio(1)
.fillColor(Color.White)
.scale({ x: this.captureBtnScale, y: this.captureBtnScale, z: this.captureBtnScale })
.enabled(this.isTakePictureEnabled)
.onTouch(async (event: TouchEvent) => {
if (event.type === TouchType.Down) {
animateTo(
{ duration: 125, curve: Curve.Sharp, delay: 0 },
() => {
this.captureBtnScale = 0.85
})
} else if (event.type === TouchType.Up) {
animateTo(
{ duration: 125, curve: Curve.Sharp, delay: 0,
onFinish: () => {
this.captureBtnScale = 1
} },
() => {
this.captureBtnScale = 1
})
this.isTakePictureEnabled = false
CameraService.takePicture()
this.isTakePictureEnabled = true
}
})
}.width(76).aspectRatio(1)
}.size({ width: '100%', height: 76 }).justifyContent(FlexAlign.Center)
}.width('100%').height('100%').backgroundColor(Color.Black)
.gesture(
PanGesture({ direction: PanDirection.Left | PanDirection.Right })
.onActionEnd(() => {
router.back()
})
)
}
}

View File

@ -1,192 +0,0 @@
/*
* 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 mediaLibrary from '@ohos.multimedia.mediaLibrary'
import DateTimeUtil from '../../model/DateTimeUtil'
import Logger from '../../model/Logger'
const TAG = 'MediaUtils'
export default class MediaUtils {
private mediaTest: mediaLibrary.MediaLibrary = mediaLibrary.getMediaLibrary(globalThis.context)
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(TAG, `displayName = ${displayName},mediaType = ${mediaType}`)
let publicPath = await this.mediaTest.getPublicDirectory(info.directory)
Logger.info(TAG, `publicPath = ${publicPath}`)
try {
return await this.mediaTest.createAsset(mediaType, displayName, publicPath)
} catch (err) {
Logger.info(TAG, `createAsset err ` + JSON.stringify(err))
}
}
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(TAG, `fetchFileResult.getCount() = ${fetchFileResult.getCount()}`)
const fileAsset = await fetchFileResult.getFirstObject()
return fileAsset
}
}
async getFdPath(fileAsset: any) {
let fd = await fileAsset.open('Rw')
Logger.info(TAG, `fd = ${fd}`)
return fd
}
async getFileAssetsAlbum(path) {
let fileKeyObj = mediaLibrary.FileKey
// ALBUM_NAME
let fetchOp = {
selections: `${fileKeyObj.RELATIVE_PATH}=?`,
selectionArgs: [`${path}`],
}
const fetchFileResult = await this.mediaTest.getFileAssets(fetchOp)
Logger.info(TAG, `getFileAssetsAlbum,fetchFileResult.count = ${fetchFileResult.getCount()}`)
let fileAssets: Array<mediaLibrary.FileAsset> = []
if (fetchFileResult.getCount() > 0) {
fileAssets = await fetchFileResult.getAllObject()
}
return fileAssets
}
async getFileAssetsFromType(mediaType: number) {
Logger.info(TAG, `getFileAssetsFromType,mediaType = ${mediaType}`)
let fileKeyObj = mediaLibrary.FileKey
// ALBUM_NAME
let fetchOp = {
selections: `${fileKeyObj.MEDIA_TYPE}=?`,
selectionArgs: [`${mediaType}`],
}
const fetchFileResult = await this.mediaTest.getFileAssets(fetchOp)
Logger.info(TAG, `getFileAssetsFromType,fetchFileResult.count = ${fetchFileResult.getCount()}`)
let fileAssets = []
if (fetchFileResult.getCount() > 0) {
fileAssets = await fetchFileResult.getAllObject()
}
return fileAssets
}
async getAlbums() {
Logger.info(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(TAG, `deleteFile,uri = ${uri}`)
// @ts-ignore
return this.mediaTest.deleteAsset(uri)
}
onDateChange(callback: () => void) {
this.mediaTest.on('albumChange', () => {
Logger.info(TAG, 'albumChange called')
callback()
})
this.mediaTest.on('imageChange', () => {
Logger.info(TAG, 'imageChange called')
callback()
})
this.mediaTest.on('audioChange', () => {
Logger.info(TAG, 'audioChange called')
callback()
})
this.mediaTest.on('videoChange', () => {
Logger.info(TAG, 'videoChange called')
callback()
})
this.mediaTest.on('fileChange', () => {
Logger.info(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_CAMERA
break
case mediaLibrary.MediaType.AUDIO:
result.prefix = 'AUD_'
result.suffix = '.wav'
result.directory = mediaLibrary.DirectoryType.DIR_AUDIO
break
}
return result
}
}

View File

@ -1,56 +0,0 @@
/*
* 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 mediaLibrary from '@ohos.multimedia.mediaLibrary'
import Logger from '../../model/Logger'
export default class ThumbnailGetter {
private TAG = '[ThumbnailGetter]:'
public async getThumbnailInfo(width: number, height: number, uri?: string): Promise<PixelMap | undefined> {
Logger.info(`${this.TAG} getThumbnailInfo E`)
Logger.debug(`${this.TAG} getThumbnailInfo width: ${width}, height: ${height}, uri: ${JSON.stringify(uri)}`)
const fileKeyObj = mediaLibrary.FileKey;
let fetchOp: any
const media = mediaLibrary.getMediaLibrary(globalThis.context);
let publicPath: string = await media.getPublicDirectory(mediaLibrary.DirectoryType.DIR_CAMERA)
Logger.info(`${this.TAG} getThumbnailInfo media: ${media}`)
fetchOp = {
selections: `${fileKeyObj.RELATIVE_PATH}=?`,
selectionArgs: [publicPath],
order: `${fileKeyObj.DATE_ADDED} DESC LIMIT 0, 1`
}
Logger.info(`${this.TAG} getThumbnailInfo fetchOp: ${JSON.stringify(fetchOp)}`)
const fetchFileResult = await media.getFileAssets(fetchOp);
const count = fetchFileResult.getCount()
Logger.info(`${this.TAG} getThumbnailInfo fetchFileResult.getCount: ${count}`)
if (count == 0) {
return undefined
}
const lastFileAsset = await fetchFileResult.getLastObject()
await fetchFileResult.close()
if (lastFileAsset == null) {
Logger.error(`${this.TAG} getThumbnailInfo lastFileAsset is null`)
return undefined
}
const thumbnailPixelMap = lastFileAsset.getThumbnail({
width: width, height: height
})
Logger.info(`${this.TAG} getThumbnailInfo thumbnailPixelMap: ${JSON.stringify(thumbnailPixelMap)} X`)
return thumbnailPixelMap
}
}

View File

@ -1,98 +0,0 @@
/*
* Copyright 2023 Unionman Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import router from '@ohos.router';
import { GRAPHIC_TRANSFORMATION, TestButton } from './testData'
import window from '@ohos.window';
import common from '@ohos.app.ability.common';
@Entry
@Component
struct Index {
@Builder itemHead(text: Resource | string) {
Text(text)
.fontSize(20)
.height(50)
.backgroundColor('#ffeae9e9')
.width("100%")
.padding(10)
}
onPageShow() {
//获取当前窗口
var FullScreen = true;
let context = getContext(this) as common.UIAbilityContext
let windowClass = null;
try {
let promise = window.getLastWindow(context);
promise.then((data)=> {
windowClass = data;
console.info('Succeeded in obtaining the top window. Data: ' + JSON.stringify(data));
//设置全屏状态
let promise = windowClass.setFullScreen(FullScreen);
promise.then(() => {
console.info('Succeeded in enabling the full-screen mode. ');
}).catch((err) => {
console.error('Failed to enable the full-screen mode. Cause: ' + JSON.stringify(err));
});
console.info('Succeeded in obtaining the top window. Data: ' + JSON.stringify(data));
}).catch((err)=>{
console.error('Failed to obtain the top window. Cause: ' + JSON.stringify(err));
});
} catch (exception) {
console.error('Failed to obtain the top window. Cause: ' + JSON.stringify(exception));
}
}
build() {
Column() {
Text('yarward测试')
.fontSize(50)
Scroll() {
Column() {
List({ space: 5 }) {
ForEach(GRAPHIC_TRANSFORMATION, (item: TestButton, index: number) => {
ListItemGroup({ header: this.itemHead(item.title) }) {
if (item.childNodes) {
ForEach(item.childNodes, (childItem: TestButton) => {
ListItem() {
Text(childItem.title)
.width("100%")
.height(50)
.fontSize(20)
.padding(10)
.backgroundColor(Color.White)
.onClick(()=>{
router.pushUrl({url:childItem.url})
})
}
})
}
}
.divider({ strokeWidth: 1, color: Color.Black }) // 每行之间的分界线
.onClick(()=>{
console.error('onclick')
if(item.childNodes == undefined){
console.error('onclick item.childNodes == undefined')
router.pushUrl({url:item.url})
}
})
})
}
Column()
.margin({bottom:90})
}
.constraintSize({ minHeight: '100%' })
}
}
.justifyContent(FlexAlign.Center)
}
}

View File

@ -1,87 +0,0 @@
/*
* 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 { getTimeString } from '../../model/Utils'
import Logger from '../../model/Logger'
const TAG = '[Recorder.AnimateView]'
@Component
export struct AnimateView {
private timeTextNum = [0, 1, 2, 3, 4, 5]
private intervalId: number = 0
private updateTimeStr: () => void
@State timeAdd: number = 0
@State translateImage: string = '-0.2%'
@State translateText: string = '-1%'
@StorageLink('recordState') @Watch('onPlayChange') recordState: boolean = true
@StorageLink('playState') @Watch('onPlayChange') playState: boolean = true
@Link @Watch('onResetChange') resetAnimation: boolean
onPlayChange() {
Logger.info(TAG, `onPlayChange`)
this.animator()
}
animator() {
Logger.info(TAG, `animator,recordState=${this.recordState},playState=${this.playState}`)
if (this.recordState || this.playState) {
this.intervalId = setInterval(() => {
this.updateTimeStr()
this.translateImage = '16.3%'
this.translateText = '15.5%'
this.timeAdd += 1
animateTo({ duration: 1100, curve: Curve.Linear }, () => {
this.translateImage = '-0.2%'
this.translateText = '-1%'
})
}, 1000)
} else {
clearInterval(this.intervalId)
}
}
onResetChange() {
this.timeAdd = 0
}
aboutToAppear() {
this.animator()
}
build() {
Column() {
Row() {
ForEach(this.timeTextNum, item => {
Text(getTimeString(this.timeAdd, item))
.fontSize(12)
.fontColor(Color.Gray)
.textAlign(TextAlign.End)
.maxLines(1)
Blank()
.layoutWeight(1)
}, item => item.toString())
}
.width('120%')
.translate({ x: this.translateText })
Image($r('app.media.slider_time'))
.width('120%')
.height(20)
.objectFit(ImageFit.Fill)
.translate({ x: this.translateImage })
}
}
}

View File

@ -1,70 +0,0 @@
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import DateTimeUtil from '../../model/DateTimeUtil';
import Logger from '../../model/Logger';
import { Record } from './Record';
const TAG = '[Recorder.AudioItem]';
const TRANSLATE: number = -145;
@Component
export struct AudioItem {
@Link record: Record;
@State translateLeft: number = 0;
@State translateRight: number = TRANSLATE;
getTimeString() {
let date = new Date(this.record.fileAsset.dateAdded * 1000);
let dateTimeUtil = new DateTimeUtil();
return `${date.getFullYear()}/${dateTimeUtil.fill(date.getMonth() + 1)}/${dateTimeUtil.fill(date.getDate())}`;
}
build() {
Row() {
Row() {
Column() {
Text(this.record.title)
.fontSize(22)
.fontColor(Color.Black)
Text(this.getTimeString())
.fontSize(20)
.fontColor(Color.Gray)
.margin({ top: 10 })
}
.size({ width: '80%', height: '100%' })
.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.Center)
Row() {
Text(this.record.duration)
.fontSize(20)
.fontColor(Color.Gray)
}
.width('20%')
.justifyContent(FlexAlign.End)
}
.width('100%')
.padding({ top: 10, bottom: 10, left: 10, right: 10 })
.margin({ top: 15, right: 15 })
.backgroundColor('#FFFFFF')
.borderRadius(20)
}
.width('100%')
.height('15%')
.constraintSize({ minHeight: 100 })
.translate({ x: this.translateLeft, y: 0 })
}
}

View File

@ -1,102 +0,0 @@
/*
* 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 media from '@ohos.multimedia.media'
import mediaLibrary from '@ohos.multimedia.mediaLibrary'
import Logger from '../../model/Logger'
const TAG: string = '[Recorder.AudioModel]'
export class AudioModel {
private audioPlayer = undefined;
private playFile: mediaLibrary.FileAsset = undefined
private dataLoad: boolean = false
initAudioPlayer(playSrc: mediaLibrary.FileAsset, isPlay) {
this.playFile = playSrc
this.dataLoad = false
this.release()
this.audioPlayer = media.createAudioPlayer()
this.audioPlayer.on('dataLoad', () => {
Logger.info(TAG, `case dataLoad called`)
this.dataLoad = true
})
this.audioPlayer.on('stop', () => {
Logger.info(TAG, `audioPlayer stop called`)
this.audioPlayer.release()
this.audioPlayer = undefined
})
this.audioPlayer.on('error', () => {
Logger.info(TAG, `audioPlayer error called`)
})
this.audioPlayer.reset()
let fdPath = playSrc.open('r')
fdPath.then(fdNumber => {
this.audioPlayer.src = `fd://${fdNumber}`
Logger.info(TAG, `create audioPlayer success`)
})
}
release() {
if (typeof (this.audioPlayer) != `undefined`) {
Logger.info(TAG, `audioPlayer release`)
this.audioPlayer.release()
this.audioPlayer = undefined
}
}
onFinish(callback) {
console.info(`${TAG}set onFinish`)
this.audioPlayer.on('finish', () => {
Logger.info(TAG, `audioPlayer finish called`)
this.audioPlayer.seek(0)
callback()
});
}
play(callback) {
if (typeof (this.audioPlayer) != `undefined`) {
this.audioPlayer.on('play', () => {
Logger.info(TAG, `audioPlayer play called`)
callback()
})
if (this.dataLoad) {
this.audioPlayer.play()
} else {
this.audioPlayer.on('dataLoad', () => {
Logger.info(TAG, `case dataLoad called`)
this.dataLoad = true
this.audioPlayer.play()
})
}
}
}
pause(callback) {
if (typeof (this.audioPlayer) != `undefined`) {
this.audioPlayer.on('pause', () => {
Logger.info(TAG, `case pause called`)
callback()
})
this.audioPlayer.pause()
}
}
finish() {
if (typeof (this.audioPlayer) != `undefined`) {
this.audioPlayer.stop()
}
}
}

Some files were not shown because too many files have changed in this diff Show More