diff --git a/data/eTSKvStore/README_zh.md b/data/eTSKvStore/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..64fd85e24c4276ac12e8b1c558a9ad76aa308694 --- /dev/null +++ b/data/eTSKvStore/README_zh.md @@ -0,0 +1,23 @@ +# eTS分布式数据管理 + + + +### 简介 + +本示例展示了在eTS中分布式数据管理的使用,包括KVManager对象实例的创建和KVStore数据流转的使用。 + +### 使用说明 + +1、两台设备组网 + +2、在一台界面中点击右上角的流转按钮,在弹窗中选择对端设备拉起对端设备上的应用 + +3、拉起对端设备后,在界面中点击"+"按钮新增笔记卡片,点击每个卡片右上角的"X"按钮可以删除此卡片,可以看到对端设备和当前设备界面数据保持一致 + +4、操作对端设备,当前设备界面也会保持和对端设备界面显示一致 + + + +### 约束与限制 + +本示例仅支持标准系统上运行。 diff --git a/data/eTSKvStore/build.gradle b/data/eTSKvStore/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..cae0ab0036a5626c92f93fb72c5f763e9764d21b --- /dev/null +++ b/data/eTSKvStore/build.gradle @@ -0,0 +1,33 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +apply plugin: 'com.huawei.ohos.app' + +// For instructions on signature configuration, see https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404#section1112183053510 +ohos { + compileSdkVersion 7 + supportSystem "standard" +} + +buildscript { + repositories { + maven { + url 'https://repo.huaweicloud.com/repository/maven/' + } + maven { + url 'https://developer.huawei.com/repo/' + } + } + dependencies { + classpath 'com.huawei.ohos:hap:3.0.3.4' + } +} + +allprojects { + repositories { + maven { + url 'https://repo.huaweicloud.com/repository/maven/' + } + maven { + url 'https://developer.huawei.com/repo/' + } + } +} diff --git a/data/eTSKvStore/entry/build.gradle b/data/eTSKvStore/entry/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..8243c3b322a99d4203fb603bab0cafd024091fb7 --- /dev/null +++ b/data/eTSKvStore/entry/build.gradle @@ -0,0 +1,16 @@ +apply plugin: 'com.huawei.ohos.hap' +//For instructions on signature configuration, see https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404#section1112183053510 +ohos { + compileSdkVersion 7 + defaultConfig { + compatibleSdkVersion 7 + } + buildTypes { + release { + proguardOpt { + proguardEnabled false + rulesFiles 'proguard-rules.pro' + } + } + } +} diff --git a/data/eTSKvStore/entry/src/main/config.json b/data/eTSKvStore/entry/src/main/config.json new file mode 100644 index 0000000000000000000000000000000000000000..a196f4038c4c091577ac4f6e94ee6d4ce1a6adfa --- /dev/null +++ b/data/eTSKvStore/entry/src/main/config.json @@ -0,0 +1,66 @@ +{ + "app": { + "bundleName": "ohos.samples.etskvstore", + "vendor": "samples", + "version": { + "code": 1000000, + "name": "1.0.0" + } + }, + "deviceConfig": {}, + "module": { + "package": "ohos.samples.etskvstore", + "name": ".MyApplication", + "mainAbility": ".MainAbility", + "deviceType": [ + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry", + "moduleType": "entry", + "installationFree": false + }, + "abilities": [ + { + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "orientation": "unspecified", + "visible": true, + "srcPath": "MainAbility", + "name": ".MainAbility", + "srcLanguage": "ets", + "icon": "$media:icon", + "description": "$string:description_mainability", + "formsEnabled": false, + "label": "$string:entry_MainAbility", + "type": "page", + "launchType": "standard" + } + ], + "js": [ + { + "mode": { + "syntax": "ets", + "type": "pageAbility" + }, + "pages": [ + "pages/index" + ], + "name": ".MainAbility", + "window": { + "designWidth": 720, + "autoDesignWidth": false + } + } + ] + } +} \ No newline at end of file diff --git a/data/eTSKvStore/entry/src/main/ets/MainAbility/app.ets b/data/eTSKvStore/entry/src/main/ets/MainAbility/app.ets new file mode 100644 index 0000000000000000000000000000000000000000..e7c503157dc42b20bc597051ccd0ab9fc2e808d0 --- /dev/null +++ b/data/eTSKvStore/entry/src/main/ets/MainAbility/app.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export default { + onCreate() { + console.info('Application onCreate') + }, + onDestroy() { + console.info('Application onDestroy') + }, +} \ No newline at end of file diff --git a/data/eTSKvStore/entry/src/main/ets/MainAbility/common/dialog.ets b/data/eTSKvStore/entry/src/main/ets/MainAbility/common/dialog.ets new file mode 100644 index 0000000000000000000000000000000000000000..1f004c5402b1f62f7d4cd91f326eb8187a952fec --- /dev/null +++ b/data/eTSKvStore/entry/src/main/ets/MainAbility/common/dialog.ets @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 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 {DeviceDataModel} from '../model/deviceDataModel' + +@CustomDialog +export struct DeviceDialog { + controller: CustomDialogController + private deviceList: Array = [] + @Link selectedIndex: number + + build() { + Column() { + Text($r('app.string.check_device')) + .fontSize(20) + .width('100%') + .textAlign(TextAlign.Center) + .fontColor(Color.Black) + .fontWeight(FontWeight.Bold) + List() { + ForEach(this.deviceList, item => { + ListItem() { + Row() { + Text(item.deviceName) + .fontSize(20) + .width('90%') + .fontColor(Color.Black) + if (this.deviceList.indexOf(item) == this.selectedIndex) { + Image($r('app.media.checked')) + .width('8%') + .objectFit(ImageFit.Contain) + } else { + Image($r('app.media.uncheck')) + .width('8%') + .objectFit(ImageFit.Contain) + } + } + .height(55) + .onClick(() => { + var index = this.deviceList.indexOf(item) + console.log("KvStore[Dialog] select device:" + item.deviceId) + if (index === this.selectedIndex) { + console.log("KvStore[IndexPage] index === this.selectedIndex") + return; + } + this.selectedIndex = this.deviceList.indexOf(item) + }) + } + }, item => item.deviceName) + } + + Button() { + Text($r('app.string.cancel')) + .fontColor('#0D9FFB') + .width('90%') + .textAlign(TextAlign.Center) + .fontSize(20) + } + .type(ButtonType.Capsule) + .backgroundColor(Color.White) + .onClick(() => { + this.controller.close() + }) + } + .backgroundColor(Color.White) + .border({ color: Color.White, radius: 20 }) + .padding(10) + } +} \ No newline at end of file diff --git a/data/eTSKvStore/entry/src/main/ets/MainAbility/common/noteItem.ets b/data/eTSKvStore/entry/src/main/ets/MainAbility/common/noteItem.ets new file mode 100644 index 0000000000000000000000000000000000000000..0219508b79de0cfae52b4f1192d4dc1724fe1b5f --- /dev/null +++ b/data/eTSKvStore/entry/src/main/ets/MainAbility/common/noteItem.ets @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020 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 {NoteModel} from '../model/noteDataModel' + +@Component +export struct NoteListItem { + private note: NoteModel = null + private deleteNoteCallBack = null + + build() { + Column() { + if (this.note.title === '' && this.note.content === '') { + Image($r('app.media.add')) + .objectFit(ImageFit.Contain) + .width(50).height('100%') + } else { + Stack({ alignContent: Alignment.TopEnd }) { + Column() { + Text(this.note.title) + .fontColor(Color.Black) + .fontSize(20) + .height('50%') + .width('100%') + .textAlign(TextAlign.Center) + .margin({ top: 20 }) + Text(this.note.content) + .fontColor(Color.Gray) + .fontSize(18) + .width('100%') + .textAlign(TextAlign.Center) + } + .width('100%').height('100%') + + Image($r('app.media.delete')) + .width('30%') + .height('30%') + .objectFit(ImageFit.Contain) + .onClick(() => { + this.deleteNoteCallBack(this.note) + }) + } + } + } + .width('100%') + .height(120) + .backgroundColor('#DFDFF5') + .border({ width: 5, color: '#F5F5F5', radius: 10 }) + } +} \ No newline at end of file diff --git a/data/eTSKvStore/entry/src/main/ets/MainAbility/common/titleBar.ets b/data/eTSKvStore/entry/src/main/ets/MainAbility/common/titleBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..d450f70ce8fb0d28bc8a8e49a961542fe6eb2776 --- /dev/null +++ b/data/eTSKvStore/entry/src/main/ets/MainAbility/common/titleBar.ets @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2020 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 {DeviceDialog} from '../common/dialog' +import featureAbility from '@ohos.ability.featureAbility' +import {RemoteDeviceModel} from '../model/remoteDeviceModel' +import {DeviceDataModel} from '../model/deviceDataModel' + +const NOTES_CHANGE = 'notesChange' +const EXIT = 'exit' + +@Component +export struct TitleBar { + @State @Watch('selectedIndexChange') selectedIndex: number = 0 + @State deviceList: Array = [] + private startAbilityCallBack = null + private remoteDeviceModel: RemoteDeviceModel = null + @Link isDistributed: boolean + @Link dialogShow: boolean + private dialogController: CustomDialogController = new CustomDialogController({ + builder: DeviceDialog({ deviceList: this.deviceList, selectedIndex: $selectedIndex }), + autoCancel: true + }) + + clearSelectState() { + this.deviceList = [] + this.dialogShow = false + this.dialogController.close() + } + + selectDevice() { + console.log('KvStore[IndexPage] start ability ......') + this.isDistributed = true + if (this.remoteDeviceModel === null || this.remoteDeviceModel.discoverList.length <= 0) { + console.log('KvStore[IndexPage] continue unauthed device:' + JSON.stringify(this.deviceList)) + this.startAbility(this.deviceList[this.selectedIndex].deviceId) + this.clearSelectState() + return + } + console.log('KvStore[IndexPage] start ability1, needAuth:') + this.remoteDeviceModel.authenticateDevice(this.deviceList[this.selectedIndex], () => { + console.log("KvStore[IndexPage] auth and online finished") + for (var i = 0; i < this.remoteDeviceModel.deviceList.length; i++) { + if (this.remoteDeviceModel.deviceList[i].deviceName === this.deviceList[this.selectedIndex].deviceName) { + this.startAbility(this.remoteDeviceModel.deviceList[i].deviceId) + } + } + }) + console.log('KvStore[IndexPage] start ability2 ......') + this.clearSelectState() + } + + selectedIndexChange() { + console.log('KvStore[IndexPage] selectedIndexChange'); + if (this.selectedIndex == 0) { + console.log("KvStore[IndexPage] stop ability") + this.startAbilityCallBack(EXIT) + this.isDistributed = false + this.deviceList = [] + this.dialogController.close() + this.dialogShow = false + return + } + this.selectDevice() + } + + startAbility(deviceId) { + console.log('KvStore[IndexPage] startAbility deviceId:' + deviceId) + featureAbility.startAbility({ + want: { + bundleName: 'ohos.samples.etskvstore', + abilityName: 'ohos.samples.etskvstore.MainAbility', + deviceId: deviceId, + parameters: { + isFA: 'FA' + } + } + }).then((data) => { + console.log('KvStore[IndexPage] start ability finished:' + JSON.stringify(data)) + this.startAbilityCallBack(NOTES_CHANGE) + }); + } + + showDialog() { + this.dialogShow = true + this.deviceList = []; + this.remoteDeviceModel.registerDeviceListCallback(() => { + console.info('KvStore[IndexPage] registerDeviceListCallback, callback entered') + this.deviceList.push({ + deviceId: '0', + deviceName: 'Local device', + deviceType: 0, + checked: false + }) + var deviceTempList = this.remoteDeviceModel.discoverList.length > 0 ? this.remoteDeviceModel.discoverList : this.remoteDeviceModel.deviceList; + for (var i = 0; i < deviceTempList.length; i++) { + console.info('KvStore[IndexPage] device ' + i + '/' + deviceTempList.length + + ' deviceId=' + deviceTempList[i].deviceId + ' deviceName=' + deviceTempList[i].deviceName + + ' deviceType=' + deviceTempList[i].deviceType) + this.deviceList.push({ + deviceId: deviceTempList[i].deviceId, + deviceName: deviceTempList[i].deviceName, + deviceType: deviceTempList[i].deviceType, + checked: (this.selectedIndex === i) + }) + } + }) + this.dialogController.open() + } + + build() { + Row() { + Text($r("app.string.title")) + .width('82%') + .fontColor(Color.White) + .fontSize(20) + Button() { + Image($r('app.media.ic_hop_normal')) + .width(70).height(40) + .objectFit(ImageFit.Contain) + } + .type(ButtonType.Normal) + .backgroundColor('#0D9FFB') + .onClick(() => { + console.info('KvStore[IndexPage] showDialog start') + this.showDialog() + }) + } + .height(50).width('100%') + .backgroundColor('#0D9FFB') + .padding({ left: 15, right: 15 }) + } +} \ No newline at end of file diff --git a/data/eTSKvStore/entry/src/main/ets/MainAbility/model/deviceDataModel.ets b/data/eTSKvStore/entry/src/main/ets/MainAbility/model/deviceDataModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..5de30665fdbccd671555a80d4e640baa3b21ef4e --- /dev/null +++ b/data/eTSKvStore/entry/src/main/ets/MainAbility/model/deviceDataModel.ets @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class DeviceDataModel{ + deviceId: string + deviceName: string + deviceType: number + checked: boolean + + constructor(deviceId: string, deviceName: string, deviceType: number, checked: boolean) { + this.deviceId = deviceId + this.deviceName = deviceName + this.deviceType = deviceType + this.checked = checked + } +} \ No newline at end of file diff --git a/data/eTSKvStore/entry/src/main/ets/MainAbility/model/kvStoreModel.ets b/data/eTSKvStore/entry/src/main/ets/MainAbility/model/kvStoreModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..4b62c12cd6d3e16b2f407866e024f61807817073 --- /dev/null +++ b/data/eTSKvStore/entry/src/main/ets/MainAbility/model/kvStoreModel.ets @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2021 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 distributedData from '@ohos.data.distributeddata' + +const STORE_ID = 'etskvstore_test' + +export class KvStoreModel { + kvManager + kvStore + + constructor() { + } + + createKvStore(callback) { + if ((typeof (this.kvStore) != 'undefined')) { + callback() + return; + } + var config = { + bundleName: 'ohos.samples.etskvstore', + userInfo: { + userId: '0', + userType: 0 + } + }; + let self = this; + console.info('[KvStoreModel] createKVManager begin') + distributedData.createKVManager(config).then((manager) => { + console.info('[KvStoreModel] createKVManager success, kvManager=' + JSON.stringify(manager)) + self.kvManager = manager; + let options = { + createIfMissing: true, + encrypt: false, + backup: false, + autoSync: true, + kvStoreType: 1, + securityLevel: 3, + }; + console.info('[KvStoreModel] kvManager.getKVStore begin') + self.kvManager.getKVStore(STORE_ID, options).then((store) => { + console.info('[KvStoreModel] getKVStore success, kvStore=' + store) + self.kvStore = store + callback() + }) + console.info('kvstore[KvStoreModel] kvManager.getKVStore end') + }); + console.info('kvstore[KvStoreModel] createKVManager end') + } + + put(key, value) { + console.info('[KvStoreModel] kvStore.put ' + key + '=' + value); + this.kvStore.put(key, value).then((data) => { + console.info('[KvStoreModel] kvStore.put ' + key + ' finished, data=' + JSON.stringify(data)) + }).catch((err) => { + console.error('[KvStoreModel] kvStore.put ' + key + ' failed, ' + JSON.stringify(err)) + }); + } + + setOnMessageReceivedListener(msg, callback) { + console.info('[KvStoreModel] setOnMessageReceivedListener ' + msg) + let self = this + this.createKvStore(() => { + console.info('[KvStoreModel] kvStore.on(dataChange) begin') + self.kvStore.on('dataChange', 1, (data) => { + console.info('[KvStoreModel] dataChange, ' + JSON.stringify(data)); + console.info('[KvStoreModel] 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 + console.info('[KvStoreModel] Entries receive ' + msg + '=' + value) + callback(value) + return; + } + } + }); + console.info('[KvStoreModel] kvStore.on(dataChange) end') + }) + } +} \ No newline at end of file diff --git a/data/eTSKvStore/entry/src/main/ets/MainAbility/model/noteDataModel.ets b/data/eTSKvStore/entry/src/main/ets/MainAbility/model/noteDataModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..81c42abcb5f574b8962f11c8db848b0221db2693 --- /dev/null +++ b/data/eTSKvStore/entry/src/main/ets/MainAbility/model/noteDataModel.ets @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export class NoteModel { + title: string + content: string + + constructor(title: string, content: string) { + this.title = title + this.content = content + } +} + +export function transStrToNoteModel(str: string): Array { + let noteList: Array = [] + var notes = JSON.parse(str) + console.info('[NoteModel]notes.length = ' + notes.length) + for (var note in notes) { + noteList.push({ title: notes[note].title, content: notes[note].content }) + } + return noteList +} \ No newline at end of file diff --git a/data/eTSKvStore/entry/src/main/ets/MainAbility/model/remoteDeviceModel.ets b/data/eTSKvStore/entry/src/main/ets/MainAbility/model/remoteDeviceModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..aeddba696db9bea0d93119fb8c186db8fe23f462 --- /dev/null +++ b/data/eTSKvStore/entry/src/main/ets/MainAbility/model/remoteDeviceModel.ets @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import deviceManager from '@ohos.distributedHardware.deviceManager' + +var SUBSCRIBE_ID = 100 + +export class RemoteDeviceModel { + deviceList = [] + discoverList = [] + callback + authCallback + deviceManager + + constructor() { + } + + registerDeviceListCallback(callback) { + if (typeof (this.deviceManager) != 'undefined') { + this.registerDeviceListCallbackImplement(callback) + return + } + console.log('[RemoteDeviceModel] deviceManager.createDeviceManager begin') + let self = this + deviceManager.createDeviceManager("ohos.samples.etskvstore", (error, value) => { + if (error) { + console.error('[RemoteDeviceModel] createDeviceManager failed.') + return; + } + self.deviceManager = value + self.registerDeviceListCallbackImplement(callback) + console.log('[RemoteDeviceModel] createDeviceManager callback returned, error=' + error + ' value=' + value) + }); + console.log('[RemoteDeviceModel] deviceManager.createDeviceManager end') + } + + deviceStateChangeActionOnline(device) { + this.deviceList[this.deviceList.length] = device + console.info('[RemoteDeviceModel] online, device list=' + JSON.stringify(this.deviceList)) + this.callback() + if (this.authCallback != null) { + this.authCallback() + this.authCallback = null + } + } + + deviceStateChangeActionReady(device) { + if (this.deviceList.length <= 0) { + this.callback() + return + } + let list = new Array() + for (let i = 0; i < this.deviceList.length; i++) { + if (this.deviceList[i].deviceId != device.deviceId) { + list[i] = device + } + } + this.deviceList = list + console.info('[RemoteDeviceModel] ready, device list=' + JSON.stringify(device)) + this.callback() + } + + deviceStateChangeActionOffline(device) { + if (this.deviceList.length <= 0) { + this.callback() + return + } + for (let j = 0; j < this.deviceList.length; j++) { + if (this.deviceList[j ].deviceId == device.deviceId) { + this.deviceList[j] = device + break + } + } + console.info('[RemoteDeviceModel] offline, device list=' + JSON.stringify(this.deviceList)) + this.callback() + } + + registerDeviceListCallbackImplement(callback) { + console.info('[RemoteDeviceModel] registerDeviceListCallback') + this.callback = callback + if (this.deviceManager === undefined) { + console.error('[RemoteDeviceModel] deviceManager has not initialized') + this.callback() + return + } + console.info('[RemoteDeviceModel] getTrustedDeviceListSync begin') + let list = this.deviceManager.getTrustedDeviceListSync() + console.info('[RemoteDeviceModel] getTrustedDeviceListSync end, deviceList=' + JSON.stringify(list)) + if (typeof (list) != 'undefined' && typeof (list.length) != 'undefined') { + this.deviceList = list + } + this.callback() + console.info('[RemoteDeviceModel] callback finished'); + let self = this; + this.deviceManager.on('deviceStateChange', (data) => { + if (data == null) { + return + } + console.info('[RemoteDeviceModel] deviceStateChange data=' + JSON.stringify(data)) + switch (data.action) { + case deviceManager.DeviceStateChangeAction.ONLINE: + self.deviceStateChangeActionOnline(data.device) + break; + case deviceManager.DeviceStateChangeAction.READY: + self.deviceStateChangeActionReady(data.device) + break; + case deviceManager.DeviceStateChangeAction.OFFLINE: + case deviceManager.DeviceStateChangeAction.CHANGE: + self.deviceStateChangeActionOffline(data.device) + break + default: + break + } + }); + this.deviceManager.on('deviceFound', (data) => { + if (data == null) { + return + } + console.info('[RemoteDeviceModel] deviceFound data=' + JSON.stringify(data)) + self.deviceFound(data) + }); + this.deviceManager.on('discoverFail', (data) => { + console.info('[RemoteDeviceModel] discoverFail data=' + JSON.stringify(data)) + }); + this.deviceManager.on('serviceDie', () => { + console.error('[RemoteDeviceModel] serviceDie') + }); + this.startDeviceDiscovery() + } + + deviceFound(data) { + for (var i = 0;i < this.discoverList.length; i++) { + if (this.discoverList[i].deviceId == data.device.deviceId) { + console.info('[RemoteDeviceModel] device founded ignored') + return + } + } + this.discoverList[this.discoverList.length] = data.device + console.info('[RemoteDeviceModel] deviceFound self.discoverList=' + this.discoverList) + this.callback(); + } + + startDeviceDiscovery() { + SUBSCRIBE_ID = Math.floor(65536 * Math.random()) + var info = { + subscribeId: SUBSCRIBE_ID, + mode: 0xAA, + medium: 2, + freq: 2, + isSameAccount: false, + isWakeRemote: true, + capability: 0 + }; + console.info('[RemoteDeviceModel] startDeviceDiscovery ' + SUBSCRIBE_ID) + this.deviceManager.startDeviceDiscovery(info) + } + + unregisterDeviceListCallback() { + console.info('[RemoteDeviceModel] stopDeviceDiscovery ' + SUBSCRIBE_ID) + this.deviceManager.stopDeviceDiscovery(SUBSCRIBE_ID); + this.deviceManager.off('deviceStateChange') + this.deviceManager.off('deviceFound') + this.deviceManager.off('discoverFail') + this.deviceManager.off('serviceDie') + this.deviceList = [] + this.discoverList = [] + } + + authenticateDevice(device, callBack) { + console.info('[RemoteDeviceModel] authenticateDevice ' + JSON.stringify(device)); + for (let i = 0; i < this.discoverList.length; i++) { + if (this.discoverList[i].deviceId != device.deviceId) { + continue + } + let extraInfo = { + 'targetPkgName': 'ohos.samples.etskvstore', + 'appName': 'Distributed kvstore', + 'appDescription': 'Distributed kvstore', + 'business': '0' + } + let authParam = { + 'authType': 1, + 'appIcon': '', + 'appThumbnail': '', + 'extraInfo': extraInfo + } + this.deviceManager.authenticateDevice(device, authParam, (err, data) => { + if (err) { + console.info('[RemoteDeviceModel] authenticateDevice error:' + JSON.stringify(err)) + this.authCallback = null + return + } + console.info('[RemoteDeviceModel] authenticateDevice succeed:' + JSON.stringify(data)) + this.authCallback = callBack + }) + } + } +} \ No newline at end of file diff --git a/data/eTSKvStore/entry/src/main/ets/MainAbility/pages/index.ets b/data/eTSKvStore/entry/src/main/ets/MainAbility/pages/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..4a057784f65ba907b18b8d4a2a803141e37b2bad --- /dev/null +++ b/data/eTSKvStore/entry/src/main/ets/MainAbility/pages/index.ets @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2020 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 featureAbility from '@ohos.ability.featureAbility' +import {NoteListItem} from '../common/noteItem' +import {TitleBar} from '../common/titleBar' +import {KvStoreModel} from '../model/kvStoreModel' +import {RemoteDeviceModel} from '../model/remoteDeviceModel' +import {NoteModel, transStrToNoteModel} from '../model/noteDataModel' + +const NOTES_CHANGE = 'notesChange'; +const EXIT = 'exit' +let kvStoreModel: KvStoreModel = new KvStoreModel() +let noteList: Array = [{ title: '', content: '' }] +let notesNum: number = 0 + +@Entry +@Component +struct Index { + @State notes: Array = [{ title: '', content: '' }] + @State dialogShow: boolean = false + @State isDistributed: boolean = false + private remoteDeviceModel: RemoteDeviceModel = new RemoteDeviceModel() + + aboutToAppear() { + featureAbility.getWant((error, want) => { + console.info('KvStore[IndexPage] featureAbility.getWant =' + JSON.stringify(want.parameters)); + if (want.parameters.isFA === 'FA') { + this.isDistributed = true + } + }) + kvStoreModel.setOnMessageReceivedListener(NOTES_CHANGE, (value) => { + console.info('kvstore[IndexPage] NOTES_CHANGE' + value) + if (this.isDistributed) { + if (value.search(EXIT) != -1) { + console.info('[json]EXIT' + EXIT) + featureAbility.terminateSelf((error) => { + console.info('kvstore[IndexPage] terminateSelf finished, error=' + error) + }); + } else { + var str = value.substring(0, value.lastIndexOf('}]') + 2) + noteList = transStrToNoteModel(str) + var strNum = value.substring(value.lastIndexOf('numBegin') + 'numBegin'.length, value.lastIndexOf('numEnd')) + notesNum = parseInt(strNum) + } + } + }) + setInterval(() => { + if (!this.dialogShow) { + this.notes = noteList + } + }, 500) + } + + deleteNoteCallBack(item) { + console.log('KvStore[IndexPage] deleteNote' + item); + var index = noteList.indexOf(item) + this.notes = [] + for (let i = 0;i < noteList.length; i++) { + if (i != index) { + this.notes.push(noteList[i]) + } + } + noteList = this.notes + kvStoreModel.put(NOTES_CHANGE, JSON.stringify(noteList) + 'numBegin' + notesNum + 'numEnd') + } + + startAbilityCallBack(key) { + console.log('KvStore[IndexPage] startAbilityCallBack' + key); + if (NOTES_CHANGE === key) { + kvStoreModel.put(NOTES_CHANGE, JSON.stringify(noteList) + 'numBegin' + notesNum + 'numEnd') + } + if (EXIT === key) { + kvStoreModel.put(NOTES_CHANGE, EXIT) + } + } + + build() { + Column() { + TitleBar({ + startAbilityCallBack: this.startAbilityCallBack, + remoteDeviceModel: this.remoteDeviceModel, + isDistributed: $isDistributed, + dialogShow: $dialogShow + }) + + Grid() { + ForEach(this.notes, item => { + GridItem() { + NoteListItem({ + note: item, + deleteNoteCallBack: this.deleteNoteCallBack + }) + } + .onClick(() => { + console.info('KvStore[IndexPage] GridItem.click' + item.title); + if (item.title === '' && item.content === '') { + notesNum += 1 + noteList[noteList.length-1] = { title: '笔记' + notesNum, content: '笔记内容' } + noteList.push({ title: '', content: '' }) + this.notes = noteList + if (this.isDistributed) { + kvStoreModel.put(NOTES_CHANGE, JSON.stringify(noteList) + 'numBegin' + notesNum + 'numEnd') + } + } + }) + }, item => item.title) + } + .columnsTemplate('1fr 1fr 1fr') + .columnsGap(10) + .rowsGap(10) + .padding(10) + .margin({ bottom: 50 }) + } + } + + onDestroy() { + if(this.remoteDeviceModel != null) { + this.remoteDeviceModel.unregisterDeviceListCallback() + } + if (this.isDistributed) { + this.isDistributed = false + } + } +} \ No newline at end of file diff --git a/data/eTSKvStore/entry/src/main/resources/base/element/string.json b/data/eTSKvStore/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..818c149ace0a885f9cf8a97545189e303a9d247b --- /dev/null +++ b/data/eTSKvStore/entry/src/main/resources/base/element/string.json @@ -0,0 +1,32 @@ +{ + "string": [ + { + "name": "entry_MainAbility", + "value": "eTSKvStore" + }, + { + "name": "description_mainability", + "value": "eTSKvStore Ability" + }, + { + "name": "title", + "value": "eTSKvStore" + }, + { + "name": "check_device", + "value": "Check device" + }, + { + "name": "cancel", + "value": "Cancel" + }, + { + "name": "note", + "value": "Note" + }, + { + "name": "note_content", + "value": "Note content" + } + ] +} \ No newline at end of file diff --git a/data/eTSKvStore/entry/src/main/resources/base/media/add.png b/data/eTSKvStore/entry/src/main/resources/base/media/add.png new file mode 100644 index 0000000000000000000000000000000000000000..e265f83c48e4a7f92b4466cd331033302b7f6a56 Binary files /dev/null and b/data/eTSKvStore/entry/src/main/resources/base/media/add.png differ diff --git a/data/eTSKvStore/entry/src/main/resources/base/media/back.png b/data/eTSKvStore/entry/src/main/resources/base/media/back.png new file mode 100644 index 0000000000000000000000000000000000000000..29959451a929c75464876f9a6e668f849e573fe9 Binary files /dev/null and b/data/eTSKvStore/entry/src/main/resources/base/media/back.png differ diff --git a/data/eTSKvStore/entry/src/main/resources/base/media/checked.png b/data/eTSKvStore/entry/src/main/resources/base/media/checked.png new file mode 100644 index 0000000000000000000000000000000000000000..a77ded514ac884365ec515801bb34c68e6e5b7f8 Binary files /dev/null and b/data/eTSKvStore/entry/src/main/resources/base/media/checked.png differ diff --git a/data/eTSKvStore/entry/src/main/resources/base/media/delete.png b/data/eTSKvStore/entry/src/main/resources/base/media/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..03e869ba69a42a8025fd2d1b828536dbd989b711 Binary files /dev/null and b/data/eTSKvStore/entry/src/main/resources/base/media/delete.png differ diff --git a/data/eTSKvStore/entry/src/main/resources/base/media/ic_hop_normal.png b/data/eTSKvStore/entry/src/main/resources/base/media/ic_hop_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..435ec58bbde7bc034fe558dc890af0b653ae2e2f Binary files /dev/null and b/data/eTSKvStore/entry/src/main/resources/base/media/ic_hop_normal.png differ diff --git a/data/eTSKvStore/entry/src/main/resources/base/media/icon.png b/data/eTSKvStore/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/data/eTSKvStore/entry/src/main/resources/base/media/icon.png differ diff --git a/data/eTSKvStore/entry/src/main/resources/base/media/uncheck.png b/data/eTSKvStore/entry/src/main/resources/base/media/uncheck.png new file mode 100644 index 0000000000000000000000000000000000000000..cba71b7ec168e67e261151ee8cb9e950f53e7cbb Binary files /dev/null and b/data/eTSKvStore/entry/src/main/resources/base/media/uncheck.png differ diff --git a/data/eTSKvStore/entry/src/main/resources/en/element/string.json b/data/eTSKvStore/entry/src/main/resources/en/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..818c149ace0a885f9cf8a97545189e303a9d247b --- /dev/null +++ b/data/eTSKvStore/entry/src/main/resources/en/element/string.json @@ -0,0 +1,32 @@ +{ + "string": [ + { + "name": "entry_MainAbility", + "value": "eTSKvStore" + }, + { + "name": "description_mainability", + "value": "eTSKvStore Ability" + }, + { + "name": "title", + "value": "eTSKvStore" + }, + { + "name": "check_device", + "value": "Check device" + }, + { + "name": "cancel", + "value": "Cancel" + }, + { + "name": "note", + "value": "Note" + }, + { + "name": "note_content", + "value": "Note content" + } + ] +} \ No newline at end of file diff --git a/data/eTSKvStore/entry/src/main/resources/zh/element/string.json b/data/eTSKvStore/entry/src/main/resources/zh/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..5617a1d22bf3011c4e3e22860c4508412ed97885 --- /dev/null +++ b/data/eTSKvStore/entry/src/main/resources/zh/element/string.json @@ -0,0 +1,32 @@ +{ + "string": [ + { + "name": "entry_MainAbility", + "value": "eTSKvStore" + }, + { + "name": "description_mainability", + "value": "eTSKvStore Ability" + }, + { + "name": "title", + "value": "分布式数据管理" + }, + { + "name": "check_device", + "value": "选择设备" + }, + { + "name": "cancel", + "value": "取消" + }, + { + "name": "note", + "value": "笔记" + }, + { + "name": "note_content", + "value": "笔记内容" + } + ] +} \ No newline at end of file diff --git a/data/eTSKvStore/screenshots/devices/main.png b/data/eTSKvStore/screenshots/devices/main.png new file mode 100644 index 0000000000000000000000000000000000000000..a76c6bcaabe077d9e479dea4d2bfae5315454c8d Binary files /dev/null and b/data/eTSKvStore/screenshots/devices/main.png differ diff --git a/data/eTSKvStore/settings.gradle b/data/eTSKvStore/settings.gradle new file mode 100644 index 0000000000000000000000000000000000000000..4773db73233a570c2d0c01a22e75321acfbf7a07 --- /dev/null +++ b/data/eTSKvStore/settings.gradle @@ -0,0 +1 @@ +include ':entry'