From cb1e45e887f45592a8dc7f16ab0274d9dce0e58a Mon Sep 17 00:00:00 2001 From: dengxiaoyu Date: Tue, 9 Sep 2025 11:40:17 +0800 Subject: [PATCH 1/4] add gimbal UX Signed-off-by: dengxiaoyu --- application/AppScope/app.json | 4 +- application/AppScope/app.json5 | 4 +- .../ets/common/constants/CommonConstants.ets | 118 +++++++- .../ets/mechextability/MechExtAbility.ets | 64 +++++ .../entry/src/main/ets/pages/MechControl.ets | 252 +++++++++++++---- .../src/main/ets/pages/TrackingLayout.ets | 262 ++++++++++++++++++ application/entry/src/main/module.json5 | 3 + .../base/media/track_layout_center.svg | 8 +- .../base/media/track_layout_center_dark.svg | 8 +- .../base/media/track_layout_left.svg | 7 +- .../base/media/track_layout_left_dark.svg | 7 +- .../base/media/track_layout_right.svg | 6 +- .../base/media/track_layout_right_dark.svg | 6 +- .../resources/base/profile/main_pages.json | 3 +- .../dark/media/intelligent_tracking.svg | 4 + .../dark/media/intelligent_tracking_dark.svg | 4 + .../dark/media/track_layout_center.svg | 4 + .../dark/media/track_layout_center_dark.svg | 4 + .../dark/media/track_layout_left.svg | 4 + .../dark/media/track_layout_left_dark.svg | 4 + .../dark/media/track_layout_right.svg | 4 + .../dark/media/track_layout_right_dark.svg | 4 + 22 files changed, 693 insertions(+), 91 deletions(-) create mode 100644 application/entry/src/main/ets/pages/TrackingLayout.ets create mode 100644 application/entry/src/main/resources/dark/media/intelligent_tracking.svg create mode 100644 application/entry/src/main/resources/dark/media/intelligent_tracking_dark.svg create mode 100644 application/entry/src/main/resources/dark/media/track_layout_center.svg create mode 100644 application/entry/src/main/resources/dark/media/track_layout_center_dark.svg create mode 100644 application/entry/src/main/resources/dark/media/track_layout_left.svg create mode 100644 application/entry/src/main/resources/dark/media/track_layout_left_dark.svg create mode 100644 application/entry/src/main/resources/dark/media/track_layout_right.svg create mode 100644 application/entry/src/main/resources/dark/media/track_layout_right_dark.svg diff --git a/application/AppScope/app.json b/application/AppScope/app.json index d98cf43d..1575faf1 100644 --- a/application/AppScope/app.json +++ b/application/AppScope/app.json @@ -2,8 +2,8 @@ "app": { "bundleName": "com.ohos.dhardwareui", "vendor": "example", - "versionCode": 10000043, - "versionName": "1.0.43", + "versionCode": 10000044, + "versionName": "1.0.44", "icon": "$media:app_icon", "label": "$string:app_name", "minAPIVersion": 12, diff --git a/application/AppScope/app.json5 b/application/AppScope/app.json5 index 6f9175cb..b5e6fcb3 100644 --- a/application/AppScope/app.json5 +++ b/application/AppScope/app.json5 @@ -16,8 +16,8 @@ "app": { "bundleName": "com.ohos.dhardwareui", "vendor": "example", - "versionCode": 10000043, - "versionName": "1.0.43", + "versionCode": 10000044, + "versionName": "1.0.44", "icon": "$media:app_icon", "label": "$string:app_name", "minAPIVersion": 12, diff --git a/application/entry/src/main/ets/common/constants/CommonConstants.ets b/application/entry/src/main/ets/common/constants/CommonConstants.ets index 1912d5e5..3207450a 100644 --- a/application/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/application/entry/src/main/ets/common/constants/CommonConstants.ets @@ -58,6 +58,122 @@ export default class CommonConstants { public static readonly MIRROR_LANGUAGES: Array = ['ug', 'ar']; // isTibetanLanguages public static readonly TIBETAN_LANGUAGES: Array = ['bo']; + + /** + * Button click Scale. + */ + public static readonly BUTTON_CLICK_SCALE: number = 0.9; + + /** + * Animation duration. + */ + public static readonly ANIMATE_DURATION: number = 150; + + /** + * Line height. + */ + public static readonly LINE_HEIGHT: number = 16; + + /** + * Text Margin top 4. + */ + public static readonly TEXT_MARGIN_TOP: number = 4; + + /** + * Text Margin left 20. + */ + public static readonly TEXT_MARGIN_LEFT: number = 20; + + /** + * Text Max font size. + */ + public static readonly MAX_FONT_SCALE: number = 1.5; + + /** + * Left Icon margin left. + */ + public static readonly LEFT_ICON_MARGIN_LEFT: number = 30; + + /** + * Other layout Icon margin left. + */ + public static readonly OTHER_ICON_MARGIN_LEFT: number = 36; + + /** + * Switch icon size. + */ + public static readonly SWITCH_ICON_SIZE: number = 20; + + /** + * Switch icon margin. + */ + public static readonly SWITCH_ICON_MARGIN: number = 3; + + /** + * Small line height. + */ + public static readonly SMALL_LINE_HEIGHT: number = 13; + + /** + * Button size. + */ + public static readonly BUTTON_SIZE: string = '40vp'; + + /** + * Small text margin top. + */ + public static readonly SMALL_TEXT_MARGIN_TOP: number = 2; + + /** + * Translate x distance. + */ + public static readonly TRANSLATE_X: number = 60; + + /** + * Animation springMotion response. + */ + public static readonly SPRING_MOTION_RESPONSE: number = 0.55; + + /** + * Animation springMotion dampingFraction. + */ + public static readonly SPRING_MOTION_DAMPING_FRACTION: number = 0.825; + + /** + * Animation springMotion overlapDuration. + */ + public static readonly SPRING_MOTION_OVERLAP_DURATION: number = 0.15; + + /** + * Normal switch margin left. + */ + public static readonly NORMAL_SWITCH_MARGIN_LEFT: number = 60; + + /** + * Max scale switch margin left. + */ + public static readonly MAX_SWITCH_MARGIN_LEFT: number = 75; + + /** + * Normal Layout margin left. + */ + public static readonly NORMAL_LAYOUT_MARGIN_LEFT: number = 55; + + /** + * Max Layout margin left. + */ + public static readonly MAX_LAYOUT_MARGIN_LEFT: number = 65; + + /** + * Bundle name. + */ + public static readonly BUNDLE_NAME: string = 'com.ohos.dhardwareui'; + + /** + * Switch off offset. + */ + public static readonly SWITCH_OFF_OFFSET: number = 4; + } export enum FontSizeScale { @@ -70,4 +186,4 @@ export enum FontSizeScale { XXL1 = 1.75, XXL2 = 2, XXL3 = 3.2, -} \ No newline at end of file +} diff --git a/application/entry/src/main/ets/mechextability/MechExtAbility.ets b/application/entry/src/main/ets/mechextability/MechExtAbility.ets index 2f91fdad..533886bc 100644 --- a/application/entry/src/main/ets/mechextability/MechExtAbility.ets +++ b/application/entry/src/main/ets/mechextability/MechExtAbility.ets @@ -16,12 +16,52 @@ import UIExtensionAbility from '@ohos.app.ability.UIExtensionAbility'; import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession'; import Want from '@ohos.app.ability.Want'; import { logger } from '../utils/Logger'; +import mechanicManager from '@ohos.distributedHardware.mechanicManager'; +import { BusinessError } from '@kit.BasicServicesKit'; const TAG: string = '[MechExtAbility]'; export default class MechExtAbility extends UIExtensionAbility { + private callback = (result: mechanicManager.TrackingEventInfo) => { + logger.info(`${TAG} result.event = ${result.event}`); + if (result.event === mechanicManager.TrackingEvent.CAMERA_TRACKING_USER_ENABLED) { + mechanicManager.setCameraTrackingEnabled(true); + AppStorage.set('isTrackingEnabled', true); + } else if (result.event === mechanicManager.TrackingEvent.CAMERA_TRACKING_USER_DISABLED) { + mechanicManager.setCameraTrackingEnabled(false); + AppStorage.set('isTrackingEnabled', false); + } + logger.info(`${TAG}trackingStateChange callback end, AppStorage.get(isTrackingEnabled) = + ${AppStorage.get('isTrackingEnabled')}`); + }; + + onTrackingStateChange() { + logger.info(`${TAG} onTrackingStateChange in`); + try { + mechanicManager.on('trackingStateChange', this.callback); + } catch (error) { + let code: number = error.code; + let message: string = error.message; + logger.error(`${TAG}trackingStateChange on failed. error.code: ${code}, message: ${message}`); + } + } + + offTrackingStateChange() { + logger.info(`${TAG} offTrackingStateChange in`); + try { + mechanicManager.off('trackingStateChange', this.callback); + } catch (error) { + let code: number = (error as BusinessError).code; + let message: string = (error as BusinessError).message; + logger.error(`${TAG}trackingStateChange off failed. error.code: ${code}, message: ${message}`); + } + } + onCreate() { logger.info(`${TAG} UIExtAbility onCreate`); + AppStorage.setOrCreate('isTrackingEnabled', true); + AppStorage.setOrCreate('currentLayout', mechanicManager.CameraTrackingLayout.DEFAULT); + this.onTrackingStateChange(); } onForeground() { @@ -34,10 +74,34 @@ export default class MechExtAbility extends UIExtensionAbility { onDestroy() { logger.info(`${TAG} UIExtAbility onDestroy`); + this.offTrackingStateChange(); } onSessionCreate(want: Want, session: UIExtensionContentSession) { logger.info(`${TAG} UIExtAbility onSessionCreate.`); + + let parameters = want.parameters; + if (!parameters) { + logger.info(`${TAG} parameters is null`); + return; + } + let callerBundleName = parameters['ohos.aafwk.param.callerBundleName']; + if (callerBundleName === undefined) { + session.terminateSelf(); + logger.error(`${TAG} callerBundleName is undefined`); + return; + } + if (typeof callerBundleName !== 'string') { + session.terminateSelf(); + logger.error(`${TAG} callerBundleName is not a string`); + return; + } + if (callerBundleName !== 'com.ohos.sceneboard') { + session.terminateSelf(); + logger.error(`${TAG} callerBundleName: ${callerBundleName} has no permission`); + return; + } + let param: Record = { 'session': session }; diff --git a/application/entry/src/main/ets/pages/MechControl.ets b/application/entry/src/main/ets/pages/MechControl.ets index 674a61aa..b8e395b0 100644 --- a/application/entry/src/main/ets/pages/MechControl.ets +++ b/application/entry/src/main/ets/pages/MechControl.ets @@ -12,125 +12,255 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { logger } from '../utils/Logger'; import mechanicManager from '@ohos.distributedHardware.mechanicManager'; -import { BusinessError } from '@ohos.base'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { curves, router } from '@kit.ArkUI'; +import { accessibility } from '@kit.AccessibilityKit'; +import { common } from '@kit.AbilityKit'; +import CommonConstants,{ FontSizeScale } from '../common/constants/CommonConstants'; const TAG = '[MechControl_Page] : '; +let localStorage = LocalStorage.getShared(); -@Entry +@Entry(localStorage) @Component struct MechControl { - @State isTrackingEnabled: boolean = false; - @State currentTrackingLayoutText: ResourceStr = $r('app.string.mech_center'); - @State currentTrackingLayoutImage: ResourceStr = $r('app.media.track_layout_center'); + @StorageLink('isTrackingEnabled') @Watch('onSwitchChange') isTrackingEnabled: boolean = + this.getDefaultValue('isTrackingEnabled', true); + @StorageLink('currentLayout') @Watch('onLayoutChange') currentLayout: mechanicManager.CameraTrackingLayout = + this.getDefaultValue('currentLayout', mechanicManager.CameraTrackingLayout.DEFAULT); + @StorageLink('currentTrackingLayoutText') currentTrackingLayoutText: ResourceStr = $r('app.string.mech_center'); + @StorageLink('currentTrackingLayoutImage') currentTrackingLayoutImage: ResourceStr = + $r('app.media.track_layout_center'); + @State fontSizeScale: number = AppStorage.get('currentFontSizeScale') as number; + private context = getContext(this) as common.UIAbilityContext; + + private getDefaultValue(key: string, defaultValue: T): T { + const value = AppStorage.get(key); + return value !== undefined ? value : defaultValue; + } + + pageTransition() { + PageTransitionEnter({ type: RouteType.None, duration: 0 }) + PageTransitionExit({ type: RouteType.None, duration: 0 }) + } + + onSwitchChange() { + logger.info(`${TAG} onSwitchChange in`); + } + + onLayoutChange() { + logger.info(`${TAG} onLayoutChange in`); + switch (this.currentLayout) { + case mechanicManager.CameraTrackingLayout.DEFAULT: + case mechanicManager.CameraTrackingLayout.MIDDLE: { + this.currentTrackingLayoutImage = $r('app.media.track_layout_center'); + this.currentTrackingLayoutText = $r('app.string.mech_center'); + break; + } + case mechanicManager.CameraTrackingLayout.LEFT: { + this.currentTrackingLayoutImage = $r('app.media.track_layout_left'); + this.currentTrackingLayoutText = $r('app.string.mech_left'); + break; + } + case mechanicManager.CameraTrackingLayout.RIGHT: { + this.currentTrackingLayoutImage = $r('app.media.track_layout_right'); + this.currentTrackingLayoutText = $r('app.string.mech_right'); + break; + } + } + } + + toggleEffectChange(){ + logger.info(`${TAG} toggleEffectChange in`); + const originalState = this.isTrackingEnabled; + try { + if (!this.isTrackingEnabled) { + logger.info(`${TAG} enable camera tracking`); + mechanicManager.setCameraTrackingEnabled(true); + this.isTrackingEnabled = true; + } else { + logger.info(`${TAG} disable camera tracking`); + mechanicManager.setCameraTrackingEnabled(false); + this.isTrackingEnabled = false; + } + } catch (error) { + let code: number = (error as BusinessError).code; + let message: string = (error as BusinessError).message; + logger.error(`${TAG} setUserOperation switch failed. error.code: ${code}, message: ${message}`); + this.isTrackingEnabled = originalState; + } + } + getSwitchStateInfo(isTrackingEnabled: boolean): string { + if (isTrackingEnabled) { + logger.info(`SwitchState is on. isTrackingEnabled: ${isTrackingEnabled}`); + return this.context.resourceManager.getStringSync($r('app.string.audio_tracking_switch_on').id); + } else { + logger.info(`SwitchState is off. isTrackingEnabled: ${isTrackingEnabled}`); + return this.context.resourceManager.getStringSync($r('app.string.audio_tracking_switch_off').id); + } + } aboutToAppear() { logger.info(`${TAG} aboutToAppear in`); + this.fontSizeScale = this.context.config?.fontSizeScale ?? FontSizeScale.DEFAULT; + logger.info(`${TAG} this.fontSizeScale: ${this.fontSizeScale}`); + try { + this.isTrackingEnabled = mechanicManager.getCameraTrackingEnabled(); + } catch (error) { + let code: number = (error as BusinessError).code; + let message: string = (error as BusinessError).message; + logger.error(`${TAG} getCameraTrackingEnabled failed. error.code: ${code}, message: ${message}`); + this.isTrackingEnabled = this.getDefaultValue('isTrackingEnabled', true); + } + + try { + this.currentLayout = mechanicManager.getCameraTrackingLayout(); + } catch (error) { + let code: number = (error as BusinessError).code; + let message: string = (error as BusinessError).message; + logger.error(`${TAG} getCameraTrackingLayout failed. error.code: ${code}, message: ${message}`); + this.currentLayout = mechanicManager.CameraTrackingLayout.DEFAULT; + } + logger.info(`${TAG} aboutToAppear end. isTrackingEnabled: ${this.isTrackingEnabled}, currentLayout: ${this.currentLayout}`); + } + + aboutToDisappear(): void { + logger.info(`${TAG} aboutToDisappear in`); } @Builder - IntelligentTracking(){ - Column(){ + IntelligentTracking() { + Column() { Button() { - Image(this.isTrackingEnabled ? $r('app.media.intelligent_tracking') :$r('app.media.intelligent_tracking_dark')) - .width(20) - .height(20) - .margin({left: 3, top: 3}) + Image(this.isTrackingEnabled ? $r('app.media.intelligent_tracking') : $r('app.media.intelligent_tracking_dark')) + .width(CommonConstants.SWITCH_ICON_SIZE) + .height(CommonConstants.SWITCH_ICON_SIZE) + .margin({ left: CommonConstants.SWITCH_ICON_MARGIN, top: CommonConstants.SWITCH_ICON_MARGIN }) } - .width('40vp') - .height('40vp') - .backgroundColor(this.isTrackingEnabled ? $r('app.color.color_0A59F7_blue') : $r('sys.color.ohos_id_color_component_normal')) + .width(CommonConstants.BUTTON_SIZE) + .height(CommonConstants.BUTTON_SIZE) + .backgroundColor(this.isTrackingEnabled ? $r('app.color.color_0A59F7_blue') : + $r('sys.color.ohos_id_color_component_normal')) + .accessibilityText($r('app.string.mech_intelligent_tracking')) + .type(ButtonType.Circle) + .clickEffect({ level: ClickEffectLevel.LIGHT, scale: CommonConstants.BUTTON_CLICK_SCALE }) .onClick(() => { - const originalState = this.isTrackingEnabled; + this.toggleEffectChange(); try { - if (!this.isTrackingEnabled) { - logger.info(`${TAG} enable camera tracking`); - mechanicManager.setCameraTrackingEnabled(true); - this.isTrackingEnabled = true; - } else { - logger.info(`${TAG} disable camera tracking`); - mechanicManager.setCameraTrackingEnabled(false); - this.isTrackingEnabled = false; - } + let eventInfo: accessibility.EventInfo = ({ + type: 'announceForAccessibility', + bundleName: CommonConstants.BUNDLE_NAME, + triggerAction: 'click', + textAnnouncedForAccessibility: this.getSwitchStateInfo(this.isTrackingEnabled) + }); + accessibility.sendAccessibilityEvent(eventInfo).then(() => { + logger.info(`Succeeded in send event, eventInfo is ${JSON.stringify(eventInfo)}`); + }).catch((err: Error) => { + logger.error('Failed to send accessibility event'); + }); } catch (error) { let code: number = (error as BusinessError).code; let message: string = (error as BusinessError).message; - logger.error(`${TAG} setCameraTrackingEnabled failed. error.code: ${code}, message: ${message}`); - this.isTrackingEnabled = originalState; + logger.error(`${TAG} sendAccessibilityEvent failed,error code: ${code},message: ${message}.`); } logger.info(`${TAG} onClick end, isTrackingEnabled = ${this.isTrackingEnabled}`); }) Text($r('app.string.mech_intelligent_tracking')) - .fontSize(12) - .lineHeight(16) + .fontSize($r('sys.float.ohos_id_text_size_body3')) + .lineHeight(CommonConstants.LINE_HEIGHT) .fontWeight(FontWeight.Medium) - .fontColor($r('app.color.color_black')) - .margin({ left: 0, top: 4, right: 0 }) + .fontColor($r('sys.color.font_primary')) + .margin({ top: CommonConstants.TEXT_MARGIN_TOP }) .textAlign(TextAlign.Center) + .maxFontScale(CommonConstants.MAX_FONT_SCALE) - Text(this.isTrackingEnabled ? $r('app.string.mech_enable'): $r('app.string.mech_close')) - .fontSize(10) - .lineHeight(13) + Text(this.isTrackingEnabled ? $r('app.string.mech_enable') : $r('app.string.mech_close')) + .fontSize($r('sys.float.Caption_M')) + .lineHeight(CommonConstants.SMALL_LINE_HEIGHT) .fontWeight(FontWeight.Regular) - .fontColor($r('app.color.color_black')) - .margin({ top: 2 }) + .fontColor($r('sys.color.font_secondary')) + .margin({ top: CommonConstants.SMALL_TEXT_MARGIN_TOP }) .textAlign(TextAlign.Center) + .maxFontScale(CommonConstants.MAX_FONT_SCALE) } + .transition(TransitionEffect.OPACITY.animation({ duration: CommonConstants.ANIMATE_DURATION, curve: Curve.Sharp })) + .translate({ x: this.isTrackingEnabled ? 0 : CommonConstants.TRANSLATE_X }) + .animation({ + curve: curves.springMotion(CommonConstants.SPRING_MOTION_RESPONSE, + CommonConstants.SPRING_MOTION_DAMPING_FRACTION, CommonConstants.SPRING_MOTION_OVERLAP_DURATION) + }) + .margin({ + left: this.isTrackingEnabled ? + (this.fontSizeScale > FontSizeScale.XL ? CommonConstants.NORMAL_SWITCH_MARGIN_LEFT : + CommonConstants.MAX_SWITCH_MARGIN_LEFT) : + (this.fontSizeScale > FontSizeScale.XL ? CommonConstants.NORMAL_SWITCH_MARGIN_LEFT : + CommonConstants.MAX_SWITCH_MARGIN_LEFT) - CommonConstants.SWITCH_OFF_OFFSET + }) } @Builder - TrackingLayout(){ - Column(){ + TrackingLayout() { + Column() { Button() { Image(this.currentTrackingLayoutImage) - .width(20) - .height(20) + .width(CommonConstants.SWITCH_ICON_SIZE) + .height(CommonConstants.SWITCH_ICON_SIZE) } - .width('40vp') - .height('40vp') + .width(CommonConstants.BUTTON_SIZE) + .height(CommonConstants.BUTTON_SIZE) + .accessibilityText($r('app.string.mech_tracking_layout')) .backgroundColor($r('app.color.color_0A59F7_blue')) + .type(ButtonType.Circle) + .clickEffect({ level: ClickEffectLevel.LIGHT, scale: CommonConstants.BUTTON_CLICK_SCALE }) .onClick(() => { logger.info(`${TAG} onClick TrackingLayout in`); + router.pushUrl({ url: 'pages/TrackingLayout' }, () => { + }) }) Text($r('app.string.mech_tracking_layout')) - .fontSize(12) - .lineHeight(16) + .fontSize($r('sys.float.ohos_id_text_size_body3')) + .lineHeight(CommonConstants.LINE_HEIGHT) .fontWeight(FontWeight.Medium) - .fontColor($r('app.color.color_black')) - .margin({ left: 0, top: 4, right: 0 }) + .fontColor($r('sys.color.font_primary')) + .margin({ top: CommonConstants.TEXT_MARGIN_TOP }) .textAlign(TextAlign.Center) + .maxFontScale(CommonConstants.MAX_FONT_SCALE) Text(this.currentTrackingLayoutText) - .fontSize(10) - .lineHeight(13) + .fontSize($r('sys.float.Caption_M')) + .lineHeight(CommonConstants.SMALL_LINE_HEIGHT) .fontWeight(FontWeight.Regular) - .fontColor($r('app.color.color_black')) - .margin({ top: 2 }) + .fontColor($r('sys.color.font_secondary')) + .margin({ top: CommonConstants.SMALL_TEXT_MARGIN_TOP }) .textAlign(TextAlign.Center) + .maxFontScale(CommonConstants.MAX_FONT_SCALE) } + .transition(TransitionEffect.OPACITY.animation({ duration: CommonConstants.ANIMATE_DURATION, curve: Curve.Sharp })) + .margin({ + left: this.fontSizeScale > FontSizeScale.DEFAULT ? CommonConstants.NORMAL_LAYOUT_MARGIN_LEFT : + CommonConstants.MAX_LAYOUT_MARGIN_LEFT + }) } build() { Column() { + Row() { + this.IntelligentTracking(); - Flex({ - direction: FlexDirection.Row, - justifyContent: FlexAlign.SpaceEvenly, - alignItems: ItemAlign.Center - }) { - this.IntelligentTracking(); + if (this.isTrackingEnabled) { + this.TrackingLayout(); + } - if (this.isTrackingEnabled) { - this.TrackingLayout(); } - } - .width('100%') - .height('100%') - + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Start) } .width('100%') .height('100%') diff --git a/application/entry/src/main/ets/pages/TrackingLayout.ets b/application/entry/src/main/ets/pages/TrackingLayout.ets new file mode 100644 index 00000000..a2830017 --- /dev/null +++ b/application/entry/src/main/ets/pages/TrackingLayout.ets @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { logger } from '../utils/Logger'; +import { router } from '@kit.ArkUI'; +import mechanicManager from '@ohos.distributedHardware.mechanicManager'; +import { BusinessError } from '@kit.BasicServicesKit'; +import CommonConstants from '../common/constants/CommonConstants'; + +const TAG = '[TrackingLayout_Page] : '; +let localStorage = LocalStorage.getShared(); + +@Entry(localStorage) +@Component +struct TrackingLayout { + @State trackingLayoutLeftImage: ResourceStr = $r('app.media.track_layout_left'); + @State trackingLayoutRightImage: ResourceStr = $r('app.media.track_layout_right'); + @State trackingLayoutCenterImage: ResourceStr = $r('app.media.track_layout_center'); + @StorageLink('currentTrackingLayoutText') currentTrackingLayoutText: ResourceStr = $r('app.string.mech_center'); + @StorageLink('currentTrackingLayoutImage') currentTrackingLayoutImage: ResourceStr = + $r('app.media.track_layout_center'); + @StorageLink('currentLayout') @Watch('onLayoutChange') currentLayout: mechanicManager.CameraTrackingLayout = + this.getDefaultValue('currentLayout', mechanicManager.CameraTrackingLayout.DEFAULT);; + @State isIconHover:boolean = false; + @State longPressCanceled: boolean = false; + + private getDefaultValue(key: string, defaultValue: T): T { + const value = AppStorage.get(key); + return value !== undefined ? value : defaultValue; + } + + pageTransition() { + PageTransitionEnter({ type: RouteType.None, duration: 0 }) + PageTransitionExit({ type: RouteType.None, duration: 0 }) + } + + aboutToAppear() { + logger.info(`${TAG} aboutToAppear in. currentLayout: ${this.currentLayout}`); + } + + onLayoutChange() { + logger.info(`${TAG} onLayoutChange in`); + switch (this.currentLayout) { + case mechanicManager.CameraTrackingLayout.DEFAULT: + case mechanicManager.CameraTrackingLayout.MIDDLE: { + this.currentTrackingLayoutImage = $r('app.media.track_layout_center'); + this.currentTrackingLayoutText = $r('app.string.mech_center'); + break; + } + case mechanicManager.CameraTrackingLayout.LEFT: { + this.currentTrackingLayoutImage = $r('app.media.track_layout_left'); + this.currentTrackingLayoutText = $r('app.string.mech_left'); + break; + } + case mechanicManager.CameraTrackingLayout.RIGHT: { + this.currentTrackingLayoutImage = $r('app.media.track_layout_right'); + this.currentTrackingLayoutText = $r('app.string.mech_right'); + break; + } + } + } + + @Builder + BackButton() { + Column() { + Button() { + SymbolGlyph($r('sys.symbol.chevron_backward')) + .fontWeight(FontWeight.Medium) + .fontSize(CommonConstants.SWITCH_ICON_SIZE) + .fontColor([$r('sys.color.ohos_id_color_primary')]) + } + .width(CommonConstants.BUTTON_SIZE) + .height(CommonConstants.BUTTON_SIZE) + .accessibilityText($r('app.string.audio_back')) + .backgroundColor($r('sys.color.ohos_id_color_component_normal')) + .onClick(() => { + logger.info(`${TAG} onClick BackButton`); + router.back(); + }) + .type(ButtonType.Circle) + .clickEffect({ level: ClickEffectLevel.LIGHT, scale: CommonConstants.BUTTON_CLICK_SCALE }) + + Text(' ') + .fontSize($r('sys.float.Body_S')) + .lineHeight(CommonConstants.LINE_HEIGHT) + .fontWeight(FontWeight.Regular) + .fontColor($r('sys.color.font_primary')) + .margin({ top: CommonConstants.TEXT_MARGIN_TOP }) + .textAlign(TextAlign.Center) + .maxFontScale(CommonConstants.MAX_FONT_SCALE) + } + .transition(TransitionEffect.OPACITY.animation({ duration: CommonConstants.ANIMATE_DURATION, curve: Curve.Sharp })) + .margin({left: CommonConstants.TEXT_MARGIN_LEFT}) + } + + @Builder + TrackingLayoutLeft() { + Column() { + Button() { + Image(this.currentLayout == mechanicManager.CameraTrackingLayout.LEFT ? $r('app.media.track_layout_left') : + $r('app.media.track_layout_left_dark')) + .width(CommonConstants.SWITCH_ICON_SIZE) + .height(CommonConstants.SWITCH_ICON_SIZE) + } + .width(CommonConstants.BUTTON_SIZE) + .height(CommonConstants.BUTTON_SIZE) + .accessibilityText($r('app.string.mech_left')) + .backgroundColor(this.currentLayout == mechanicManager.CameraTrackingLayout.LEFT ? + $r('app.color.color_0A59F7_blue') : $r('sys.color.ohos_id_color_component_normal')) + .onClick(() => { + logger.info(`${TAG} onClick TrackingLayoutLeft in`); + this.onLeftIconClick(); + }) + .type(ButtonType.Circle) + .clickEffect({ level: ClickEffectLevel.LIGHT, scale: CommonConstants.BUTTON_CLICK_SCALE }) + + Text($r('app.string.mech_left')) + .fontSize($r('sys.float.Body_S')) + .lineHeight(CommonConstants.LINE_HEIGHT) + .fontWeight(FontWeight.Regular) + .fontColor($r('sys.color.font_primary')) + .margin({ top: CommonConstants.TEXT_MARGIN_TOP }) + .textAlign(TextAlign.Center) + .maxFontScale(CommonConstants.MAX_FONT_SCALE) + } + .transition(TransitionEffect.OPACITY.animation({ duration: CommonConstants.ANIMATE_DURATION, curve: Curve.Sharp })) + .margin({ left: CommonConstants.LEFT_ICON_MARGIN_LEFT }) + } + + @Builder + TrackingLayoutCenter() { + Column() { + Button() { + Image((this.currentLayout == mechanicManager.CameraTrackingLayout.MIDDLE || + this.currentLayout == mechanicManager.CameraTrackingLayout.DEFAULT) ? + $r('app.media.track_layout_center') : + $r('app.media.track_layout_center_dark')) + .width(CommonConstants.SWITCH_ICON_SIZE) + .height(CommonConstants.SWITCH_ICON_SIZE) + } + .width(CommonConstants.BUTTON_SIZE) + .height(CommonConstants.BUTTON_SIZE) + .accessibilityText($r('app.string.mech_center')) + .backgroundColor((this.currentLayout == mechanicManager.CameraTrackingLayout.MIDDLE || + this.currentLayout == mechanicManager.CameraTrackingLayout.DEFAULT) ? $r('app.color.color_0A59F7_blue') : + $r('sys.color.ohos_id_color_component_normal')) + .onClick(() => { + logger.info(`${TAG} onClick TrackingLayoutCenter in`); + this.onCenterIconClick(); + }) + .type(ButtonType.Circle) + .clickEffect({ level: ClickEffectLevel.LIGHT, scale: CommonConstants.BUTTON_CLICK_SCALE }) + + Text($r('app.string.mech_center')) + .fontSize($r('sys.float.Body_S')) + .lineHeight(CommonConstants.LINE_HEIGHT) + .fontWeight(FontWeight.Regular) + .fontColor($r('sys.color.font_primary')) + .margin({ top: CommonConstants.TEXT_MARGIN_TOP }) + .textAlign(TextAlign.Center) + .maxFontScale(CommonConstants.MAX_FONT_SCALE) + } + .transition(TransitionEffect.OPACITY.animation({ duration: CommonConstants.ANIMATE_DURATION, curve: Curve.Sharp })) + .margin({ left: CommonConstants.OTHER_ICON_MARGIN_LEFT }) + } + + @Builder + TrackingLayoutRight() { + Column() { + Button() { + Image(this.currentLayout == mechanicManager.CameraTrackingLayout.RIGHT ? + $r('app.media.track_layout_right') : + $r('app.media.track_layout_right_dark')) + .width(CommonConstants.SWITCH_ICON_SIZE) + .height(CommonConstants.SWITCH_ICON_SIZE) + } + .width(CommonConstants.BUTTON_SIZE) + .height(CommonConstants.BUTTON_SIZE) + .accessibilityText($r('app.string.mech_right')) + .backgroundColor(this.currentLayout == mechanicManager.CameraTrackingLayout.RIGHT ? + $r('app.color.color_0A59F7_blue') : $r('sys.color.ohos_id_color_component_normal')) + .onClick(() => { + logger.info(`${TAG} onClick TrackingLayoutRight in`); + this.onRightIconClick(); + }) + .type(ButtonType.Circle) + .clickEffect({ level: ClickEffectLevel.LIGHT, scale: CommonConstants.BUTTON_CLICK_SCALE }) + + Text($r('app.string.mech_right')) + .fontSize($r('sys.float.Body_S')) + .lineHeight(CommonConstants.LINE_HEIGHT) + .fontWeight(FontWeight.Regular) + .fontColor($r('sys.color.font_primary')) + .margin({ top: CommonConstants.TEXT_MARGIN_TOP }) + .textAlign(TextAlign.Center) + .maxFontScale(CommonConstants.MAX_FONT_SCALE) + } + .transition(TransitionEffect.OPACITY.animation({ duration: CommonConstants.ANIMATE_DURATION, curve: Curve.Sharp })) + .margin({ left: CommonConstants.OTHER_ICON_MARGIN_LEFT }) + } + + build() { + Column() { + Flex({ + direction: FlexDirection.Row, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center + }) { + this.BackButton(); + this.TrackingLayoutLeft(); + this.TrackingLayoutCenter(); + this.TrackingLayoutRight(); + } + .width('100%') + .height('100%') + + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Center) + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM]) + } + + setCameraTrackingLayout(layout: mechanicManager.CameraTrackingLayout) { + logger.info(`${TAG} setCameraTrackingLayout: ${layout}`); + let originalLayout = this.currentLayout; + try { + mechanicManager.setCameraTrackingLayout(layout); + this.currentLayout = layout; + } catch (error) { + this.currentLayout = originalLayout; + let code: number = (error as BusinessError).code; + let message: string = (error as BusinessError).message; + logger.error(`${TAG} setCameraTrackingLayout failed. Layout: ${layout}, error.code: ${code}, message: ${message}`); + } + } + + onLeftIconClick = () => { + logger.info(`${TAG} onLeftIconClick in`); + this.setCameraTrackingLayout(mechanicManager.CameraTrackingLayout.LEFT); + } + + onCenterIconClick = () => { + logger.info(`${TAG} onCenterIconClick in`); + this.setCameraTrackingLayout(mechanicManager.CameraTrackingLayout.MIDDLE); + } + + onRightIconClick = () => { + logger.info(`${TAG} onRightIconClick in`); + this.setCameraTrackingLayout(mechanicManager.CameraTrackingLayout.RIGHT); + } +} \ No newline at end of file diff --git a/application/entry/src/main/module.json5 b/application/entry/src/main/module.json5 index ddfce3b7..6761ca38 100644 --- a/application/entry/src/main/module.json5 +++ b/application/entry/src/main/module.json5 @@ -66,6 +66,9 @@ }, { "name": "ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS_EXTENSION" + }, + { + "name": "ohos.permission.GONNECT_MECHANIC_HARDWARE" } ], "extensionAbilities": [ diff --git a/application/entry/src/main/resources/base/media/track_layout_center.svg b/application/entry/src/main/resources/base/media/track_layout_center.svg index 7abb97c0..490885c8 100644 --- a/application/entry/src/main/resources/base/media/track_layout_center.svg +++ b/application/entry/src/main/resources/base/media/track_layout_center.svg @@ -1,6 +1,4 @@ - - - - - + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/base/media/track_layout_center_dark.svg b/application/entry/src/main/resources/base/media/track_layout_center_dark.svg index 6dc793cd..72c6286d 100644 --- a/application/entry/src/main/resources/base/media/track_layout_center_dark.svg +++ b/application/entry/src/main/resources/base/media/track_layout_center_dark.svg @@ -1,6 +1,4 @@ - - - - - + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/base/media/track_layout_left.svg b/application/entry/src/main/resources/base/media/track_layout_left.svg index 4efb202a..9a3a28b5 100644 --- a/application/entry/src/main/resources/base/media/track_layout_left.svg +++ b/application/entry/src/main/resources/base/media/track_layout_left.svg @@ -1,5 +1,4 @@ - - - - + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/base/media/track_layout_left_dark.svg b/application/entry/src/main/resources/base/media/track_layout_left_dark.svg index e06939a7..49e54332 100644 --- a/application/entry/src/main/resources/base/media/track_layout_left_dark.svg +++ b/application/entry/src/main/resources/base/media/track_layout_left_dark.svg @@ -1,5 +1,4 @@ - - - - + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/base/media/track_layout_right.svg b/application/entry/src/main/resources/base/media/track_layout_right.svg index c7d0a930..e28476be 100644 --- a/application/entry/src/main/resources/base/media/track_layout_right.svg +++ b/application/entry/src/main/resources/base/media/track_layout_right.svg @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/base/media/track_layout_right_dark.svg b/application/entry/src/main/resources/base/media/track_layout_right_dark.svg index 343e3eb5..907fc7fe 100644 --- a/application/entry/src/main/resources/base/media/track_layout_right_dark.svg +++ b/application/entry/src/main/resources/base/media/track_layout_right_dark.svg @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/base/profile/main_pages.json b/application/entry/src/main/resources/base/profile/main_pages.json index ad262871..c9abbdea 100644 --- a/application/entry/src/main/resources/base/profile/main_pages.json +++ b/application/entry/src/main/resources/base/profile/main_pages.json @@ -2,6 +2,7 @@ "src": [ "pages/DHardwareUI", "pages/ContinueSwitch", - "pages/MechControl" + "pages/MechControl", + "pages/TrackingLayout" ] } \ No newline at end of file diff --git a/application/entry/src/main/resources/dark/media/intelligent_tracking.svg b/application/entry/src/main/resources/dark/media/intelligent_tracking.svg new file mode 100644 index 00000000..aee450d9 --- /dev/null +++ b/application/entry/src/main/resources/dark/media/intelligent_tracking.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/dark/media/intelligent_tracking_dark.svg b/application/entry/src/main/resources/dark/media/intelligent_tracking_dark.svg new file mode 100644 index 00000000..aee450d9 --- /dev/null +++ b/application/entry/src/main/resources/dark/media/intelligent_tracking_dark.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/dark/media/track_layout_center.svg b/application/entry/src/main/resources/dark/media/track_layout_center.svg new file mode 100644 index 00000000..490885c8 --- /dev/null +++ b/application/entry/src/main/resources/dark/media/track_layout_center.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/dark/media/track_layout_center_dark.svg b/application/entry/src/main/resources/dark/media/track_layout_center_dark.svg new file mode 100644 index 00000000..490885c8 --- /dev/null +++ b/application/entry/src/main/resources/dark/media/track_layout_center_dark.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/dark/media/track_layout_left.svg b/application/entry/src/main/resources/dark/media/track_layout_left.svg new file mode 100644 index 00000000..9a3a28b5 --- /dev/null +++ b/application/entry/src/main/resources/dark/media/track_layout_left.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/dark/media/track_layout_left_dark.svg b/application/entry/src/main/resources/dark/media/track_layout_left_dark.svg new file mode 100644 index 00000000..9a3a28b5 --- /dev/null +++ b/application/entry/src/main/resources/dark/media/track_layout_left_dark.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/dark/media/track_layout_right.svg b/application/entry/src/main/resources/dark/media/track_layout_right.svg new file mode 100644 index 00000000..e28476be --- /dev/null +++ b/application/entry/src/main/resources/dark/media/track_layout_right.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/application/entry/src/main/resources/dark/media/track_layout_right_dark.svg b/application/entry/src/main/resources/dark/media/track_layout_right_dark.svg new file mode 100644 index 00000000..e28476be --- /dev/null +++ b/application/entry/src/main/resources/dark/media/track_layout_right_dark.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file -- Gitee From 4c7bd822b701055fac5f18fe3e337d246cdc00c5 Mon Sep 17 00:00:00 2001 From: dengxiaoyu Date: Tue, 9 Sep 2025 14:26:47 +0800 Subject: [PATCH 2/4] del arkts err Signed-off-by: dengxiaoyu --- .../entry/src/main/ets/mechextability/MechExtAbility.ets | 2 +- application/entry/src/main/ets/pages/MechControl.ets | 9 +++++---- application/entry/src/main/ets/pages/TrackingLayout.ets | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/application/entry/src/main/ets/mechextability/MechExtAbility.ets b/application/entry/src/main/ets/mechextability/MechExtAbility.ets index 533886bc..8e6e020e 100644 --- a/application/entry/src/main/ets/mechextability/MechExtAbility.ets +++ b/application/entry/src/main/ets/mechextability/MechExtAbility.ets @@ -17,7 +17,7 @@ import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSessi import Want from '@ohos.app.ability.Want'; import { logger } from '../utils/Logger'; import mechanicManager from '@ohos.distributedHardware.mechanicManager'; -import { BusinessError } from '@kit.BasicServicesKit'; +import { BusinessError } from '@ohos.base'; const TAG: string = '[MechExtAbility]'; diff --git a/application/entry/src/main/ets/pages/MechControl.ets b/application/entry/src/main/ets/pages/MechControl.ets index b8e395b0..9334de86 100644 --- a/application/entry/src/main/ets/pages/MechControl.ets +++ b/application/entry/src/main/ets/pages/MechControl.ets @@ -15,10 +15,11 @@ import { logger } from '../utils/Logger'; import mechanicManager from '@ohos.distributedHardware.mechanicManager'; -import { BusinessError } from '@kit.BasicServicesKit'; -import { curves, router } from '@kit.ArkUI'; -import { accessibility } from '@kit.AccessibilityKit'; -import { common } from '@kit.AbilityKit'; +import { BusinessError } from '@ohos.base'; +import router from '@ohos.router'; +import curves from '@ohos.curves'; +import accessibility from '@ohos.accessibility'; +import common from '@ohos.app.ability.common'; import CommonConstants,{ FontSizeScale } from '../common/constants/CommonConstants'; const TAG = '[MechControl_Page] : '; diff --git a/application/entry/src/main/ets/pages/TrackingLayout.ets b/application/entry/src/main/ets/pages/TrackingLayout.ets index a2830017..36ed03ed 100644 --- a/application/entry/src/main/ets/pages/TrackingLayout.ets +++ b/application/entry/src/main/ets/pages/TrackingLayout.ets @@ -14,9 +14,9 @@ */ import { logger } from '../utils/Logger'; -import { router } from '@kit.ArkUI'; +import router from '@ohos.router'; import mechanicManager from '@ohos.distributedHardware.mechanicManager'; -import { BusinessError } from '@kit.BasicServicesKit'; +import { BusinessError } from '@ohos.base'; import CommonConstants from '../common/constants/CommonConstants'; const TAG = '[TrackingLayout_Page] : '; -- Gitee From 17efd077941908de95047ff2db94c046a6a3d7e5 Mon Sep 17 00:00:00 2001 From: dengxiaoyu Date: Tue, 9 Sep 2025 09:36:03 +0000 Subject: [PATCH 3/4] update application/entry/src/main/ets/mechextability/MechExtAbility.ets. Signed-off-by: dengxiaoyu --- .../ets/mechextability/MechExtAbility.ets | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/application/entry/src/main/ets/mechextability/MechExtAbility.ets b/application/entry/src/main/ets/mechextability/MechExtAbility.ets index 8e6e020e..e374d69d 100644 --- a/application/entry/src/main/ets/mechextability/MechExtAbility.ets +++ b/application/entry/src/main/ets/mechextability/MechExtAbility.ets @@ -80,28 +80,6 @@ export default class MechExtAbility extends UIExtensionAbility { onSessionCreate(want: Want, session: UIExtensionContentSession) { logger.info(`${TAG} UIExtAbility onSessionCreate.`); - let parameters = want.parameters; - if (!parameters) { - logger.info(`${TAG} parameters is null`); - return; - } - let callerBundleName = parameters['ohos.aafwk.param.callerBundleName']; - if (callerBundleName === undefined) { - session.terminateSelf(); - logger.error(`${TAG} callerBundleName is undefined`); - return; - } - if (typeof callerBundleName !== 'string') { - session.terminateSelf(); - logger.error(`${TAG} callerBundleName is not a string`); - return; - } - if (callerBundleName !== 'com.ohos.sceneboard') { - session.terminateSelf(); - logger.error(`${TAG} callerBundleName: ${callerBundleName} has no permission`); - return; - } - let param: Record = { 'session': session }; -- Gitee From 8ad1ba2e62270cb47389f2068f5ea2a0c21ba4b4 Mon Sep 17 00:00:00 2001 From: dengxiaoyu Date: Wed, 10 Sep 2025 02:52:15 +0000 Subject: [PATCH 4/4] update application/entry/src/main/module.json5. Signed-off-by: dengxiaoyu --- application/entry/src/main/module.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/entry/src/main/module.json5 b/application/entry/src/main/module.json5 index 6761ca38..70cec13a 100644 --- a/application/entry/src/main/module.json5 +++ b/application/entry/src/main/module.json5 @@ -68,7 +68,7 @@ "name": "ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS_EXTENSION" }, { - "name": "ohos.permission.GONNECT_MECHANIC_HARDWARE" + "name": "ohos.permission.CONNECT_MECHANIC_HARDWARE" } ], "extensionAbilities": [ -- Gitee