diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/FlutterInjector.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/FlutterInjector.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/FlutterInjector.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/FlutterInjector.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/app/FlutterPluginRegistry.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/app/FlutterPluginRegistry.ets new file mode 100644 index 0000000000000000000000000000000000000000..760659f83d18913991151d7c1bc51bcb0f6fd50e --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/app/FlutterPluginRegistry.ets @@ -0,0 +1,49 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 FlutterView from '../embedding/ohos/FlutterView'; +import common from '@ohos.app.ability.common'; +import PlatformViewController from '../plugin/platform/PlatformViewsController' +import Log from '../util/Log'; + +export default class FlutterPluginRegistry { + private mPlatformViewsController: PlatformViewController; + private mFlutterView: FlutterView; + private mContext: common.Context; + + constructor() { + this.mPlatformViewsController = new PlatformViewController(); + } + + attach(flutterView: FlutterView, context: common.Context): void { + this.mFlutterView = flutterView; + this.mContext = context; + } + + detach(): void { + this.mPlatformViewsController.detach(); + this.mPlatformViewsController.onDetachedFromNapi(); + this.mFlutterView = null; + this.mContext = null; + } + + destroy(): void { + this.mPlatformViewsController.onDetachedFromNapi(); + } + + onPreEngineRestart(): void{ + this.mPlatformViewsController.onPreEngineRestart(); + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngine.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngine.ets similarity index 91% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngine.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngine.ets index 48ffc063d89f9df7a16fed35c23a2c9982eda1d7..af5eecade43b9cec8c5c9f82a7ccf72034b6d9e1 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngine.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngine.ets @@ -38,6 +38,7 @@ import LocalizationChannel from './systemchannels/LocalizationChannel'; import AccessibilityChannel from './systemchannels/AccessibilityChannel'; import LocalizationPlugin from '../../plugin/localization/LocalizationPlugin' import SettingsChannel from './systemchannels/SettingsChannel'; +import PlatformViewsController from '../../plugin/platform/PlatformViewsController'; const TAG = "FlutterEngine"; @@ -67,6 +68,7 @@ export default class FlutterEngine implements EngineLifecycleListener{ private textInputPlugin: TextInputPlugin; private localizationPlugin: LocalizationPlugin; private settingsChannel: SettingsChannel; + private platformViewsController: PlatformViewsController; /** * 需要初始化的工作: @@ -77,7 +79,7 @@ export default class FlutterEngine implements EngineLifecycleListener{ * 5、初始化flutterJNI * 6、engineLifecycleListeners */ - constructor(context: common.Context, flutterLoader: FlutterLoader, flutterNapi: FlutterNapi) { + constructor(context: common.Context, flutterLoader: FlutterLoader, flutterNapi: FlutterNapi, platformViewsController: PlatformViewsController) { const injector: FlutterInjector = FlutterInjector.getInstance(); if(flutterNapi == null){ @@ -93,6 +95,12 @@ export default class FlutterEngine implements EngineLifecycleListener{ flutterLoader = injector.getFlutterLoader(); } this.flutterLoader = flutterLoader; + + if(platformViewsController == null) { + platformViewsController = new PlatformViewsController(); + } + this.platformViewsController = platformViewsController; + this.platformViewsController.attach(context, null, this.dartExecutor); } async init(context: common.Context, dartVmArgs: Array, automaticallyRegisterPlugins: boolean, @@ -142,6 +150,7 @@ export default class FlutterEngine implements EngineLifecycleListener{ dartEntrypoint: DartEntrypoint, initialRoute: string, dartEntrypointArgs: Array, + platformViewsController: PlatformViewsController, automaticallyRegisterPlugins: boolean, waitForRestorationData: boolean) { if (!this.isAttachedToNapi()) { throw new Error( @@ -157,7 +166,8 @@ export default class FlutterEngine implements EngineLifecycleListener{ const flutterEngine = new FlutterEngine( context, null, - newFlutterJNI + newFlutterJNI, + platformViewsController ); await flutterEngine.init(context, null, automaticallyRegisterPlugins, waitForRestorationData, null) return flutterEngine @@ -235,8 +245,8 @@ export default class FlutterEngine implements EngineLifecycleListener{ Log.d(TAG, "Destroying."); this.engineLifecycleListeners.forEach(listener => listener.onEngineWillDestroy()) this.flutterNapi.removeEngineLifecycleListener(this); - this.pluginRegistry.detachFromAbility() - //TODO + this.pluginRegistry.detachFromAbility(); + this.platformViewsController.onDetachedFromNapi(); } getRestorationChannel(): RestorationChannel{ @@ -254,6 +264,10 @@ export default class FlutterEngine implements EngineLifecycleListener{ getSystemLanguages(): void { return this.flutterNapi.getSystemLanguages(); } + + getPlatformViewsController(): PlatformViewsController { + return this.platformViewsController; + } } export interface EngineLifecycleListener { diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineCache.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineCache.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineCache.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineCache.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineConnectionRegistry.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineConnectionRegistry.ets similarity index 98% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineConnectionRegistry.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineConnectionRegistry.ets index 442d06295dac3089bc76c315af98098b18721533..3ca45c9f4cfc9ab2e22d6b2e9edd08afdfed4bd3 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineConnectionRegistry.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineConnectionRegistry.ets @@ -53,7 +53,7 @@ export default class FlutterEngineConnectionRegistry implements PluginRegistry, constructor(appContext: common.Context, flutterEngine: FlutterEngine, flutterLoader: FlutterLoader, group: FlutterEngineGroup) { this.flutterEngine = flutterEngine; - this.pluginBinding = new FlutterPluginBinding(appContext, this.flutterEngine.getDartExecutor(), new DefaultFlutterAssets(flutterLoader), group); + this.pluginBinding = new FlutterPluginBinding(appContext, this.flutterEngine.getDartExecutor(), new DefaultFlutterAssets(flutterLoader), group, this.flutterEngine.getPlatformViewsController()?.getRegistry()); } add(plugin: FlutterPlugin): void { @@ -173,13 +173,11 @@ export default class FlutterEngineConnectionRegistry implements PluginRegistry, private attachToAbilityInternal(ability: UIAbility): void { this.abilityPluginBinding = new FlutterEngineAbilityPluginBinding(ability); - //TODO set PlatformViewsController setSoftwareRendering attach // Notify all AbilityAware plugins that they are now attached to a new Ability. this.abilityAwarePlugins.forEach(abilityAware => abilityAware.onAttachedToAbility(this.abilityPluginBinding)); } private detachFromAbilityInternal(): void { - // TODO Deactivate PlatformViewsController. detach this.exclusiveAbility = null; this.abilityPluginBinding = null; } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineGroup.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineGroup.ets similarity index 81% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineGroup.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineGroup.ets index e7765f56f9dca2e2d05e8818c43edce9864fe63b..5e5c069fcb9ee72d0a4542b6593abebfdd24d44e 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineGroup.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineGroup.ets @@ -18,6 +18,7 @@ import common from '@ohos.app.ability.common' import FlutterLoader from './loader/FlutterLoader' import FlutterInjector from '../../FlutterInjector' import { DartEntrypoint } from './dart/DartExecutor' +import PlatformViewsController from '../../plugin/platform/PlatformViewsController' export default class FlutterEngineGroup { private activeEngines: Array = new Array(); @@ -40,7 +41,7 @@ export default class FlutterEngineGroup { let dartEntrypoint: DartEntrypoint = options.getDartEntrypoint(); let initialRoute: string = options.getInitialRoute(); let dartEntrypointArgs: Array = options.getDartEntrypointArgs(); - //TODO:接入PlatformViewsController + let platformViewsController: PlatformViewsController = options.getPlatformViewsController(); let automaticallyRegisterPlugins: boolean = options.getAutomaticallyRegisterPlugins(); let waitForRestorationData: boolean = options.getWaitForRestorationData(); @@ -48,8 +49,12 @@ export default class FlutterEngineGroup { dartEntrypoint = DartEntrypoint.createDefault(); } + if (platformViewsController == null) { + platformViewsController = new PlatformViewsController(); + } + if (this.activeEngines.length == 0) { - engine = this.createEngine(context); + engine = this.createEngine(context, platformViewsController); await engine.init(context, null, // String[]. The Dart VM has already started, this arguments will have no effect. automaticallyRegisterPlugins, // boolean. waitForRestorationData, // boolean. @@ -64,6 +69,7 @@ export default class FlutterEngineGroup { dartEntrypoint, initialRoute, dartEntrypointArgs, + platformViewsController, automaticallyRegisterPlugins, waitForRestorationData); } @@ -72,7 +78,7 @@ export default class FlutterEngineGroup { const engineToCleanUpOnDestroy = engine; engine.addEngineLifecycleListener({ onPreEngineRestart(): void { - // No-op. Not interested. + platformViewsController.onPreEngineRestart(); }, onEngineWillDestroy(): void { this.activeEngines.remove(engineToCleanUpOnDestroy); @@ -81,8 +87,8 @@ export default class FlutterEngineGroup { return engine; } - createEngine(context: common.Context): FlutterEngine { - return new FlutterEngine(context, null, null); + createEngine(context: common.Context, platformViewsController: PlatformViewsController): FlutterEngine { + return new FlutterEngine(context, null, null, platformViewsController); } } @@ -91,7 +97,7 @@ export class Options { private dartEntrypoint: DartEntrypoint; private initialRoute: string; private dartEntrypointArgs: Array; - //TODO:声明成员platformViewsController:PlatformViewsController + private platformViewsController: PlatformViewsController; private automaticallyRegisterPlugins: boolean = true; private waitForRestorationData: boolean = false; @@ -122,7 +128,10 @@ export class Options { getWaitForRestorationData(): boolean { return this.waitForRestorationData; } - //TODO:实现getPlatformViewsController + + getPlatformViewsController(): PlatformViewsController { + return this.platformViewsController; + } setDartEntrypoint(dartEntrypoint: DartEntrypoint): Options { this.dartEntrypoint = dartEntrypoint; @@ -148,5 +157,9 @@ export class Options { this.waitForRestorationData = waitForRestorationData; return this; } - //TODO:实现setPlatformViewsController + + setPlatformViewsController(platformViewsController: PlatformViewsController): Options { + this.platformViewsController = platformViewsController; + return this; + } } \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineGroupCache.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineGroupCache.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineGroupCache.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterEngineGroupCache.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterNapi.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/PathUtils.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterOverlaySurface.ets similarity index 73% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/PathUtils.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterOverlaySurface.ets index 239bc06e76c1d6ef2baeb4b64e4aed6aa2143c6f..2d63d83de313f52eba3f8fa6d2ed584f7bee44bd 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/PathUtils.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterOverlaySurface.ets @@ -13,19 +13,15 @@ * limitations under the License. */ -/** - * ohos路径获取工具 - */ -export default class PathUtils { - static getFilesDir(): string { - return null; - } +export class FlutterOverlaySurface { + + private id: number; - static getCacheDirectory(): string { - return null; + constructor(id: number) { + this.id = id } - static getDataDirectory(): string { - return null; + getId(): number { + return this.id; } } \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterShellArgs.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterShellArgs.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterShellArgs.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/FlutterShellArgs.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartExecutor.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartExecutor.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartExecutor.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartExecutor.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartMessenger.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartMessenger.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartMessenger.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartMessenger.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/PlatformMessageHandler.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/PlatformMessageHandler.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/PlatformMessageHandler.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/PlatformMessageHandler.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/ApplicationInfoLoader.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/ApplicationInfoLoader.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/ApplicationInfoLoader.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/ApplicationInfoLoader.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterApplicationInfo.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterApplicationInfo.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterApplicationInfo.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterApplicationInfo.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterLoader.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterLoader.ets similarity index 99% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterLoader.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterLoader.ets index 730da648d2c34fd3ce9e0ab7fc6755a6994d4647..9415d242aab114f2f916945d31bd870c5007c6e2 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterLoader.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterLoader.ets @@ -170,7 +170,6 @@ export default class FlutterLoader { shellArgs.push("--domain-network-policy=" + this.flutterApplicationInfo.domainNetworkPolicy); } - //todo 是否有其他需要迁移得参数 const resourceCacheMaxBytesThreshold = 1080 * 1920 * 12 * 4; shellArgs.push("--resource-cache-max-bytes-threshold=" + resourceCacheMaxBytesThreshold); diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/mutatorsstack/FlutterMutatorView.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/mutatorsstack/FlutterMutatorView.ets new file mode 100644 index 0000000000000000000000000000000000000000..f0d8581b18e4525297a02174628b1a704c7379d5 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/mutatorsstack/FlutterMutatorView.ets @@ -0,0 +1,115 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 ArrayList from '@ohos.util.ArrayList'; +import { DVModel, DVModelParameters } from '../../../view/DynamicView/dynamicView'; +import { createDVModelFromJson } from '../../../view/DynamicView/dynamicViewJson'; +import OhosTouchProcessor from '../../ohos/OhosTouchProcessor'; +import { FlutterMutator, FlutterMutatorsStack } from './FlutterMutatorsStack' + +export class FlutterMutatorView { + private mutatorsStack: FlutterMutatorsStack; + private screenDensity: number; + private left: number; + private top: number; + private prevLeft: number; + private prevTop: number; + private ohosTouchProcessor: OhosTouchProcessor; + private onTouch = (touchEvent) => { + switch (touchEvent.type) { + case TouchType.Down: + this.prevLeft = this.left; + this.prevTop = this.top; + this.model.params["translateX"] = this.left; + this.model.params["translateY"] = this.top; + break; + case TouchType.Move: + this.model.params["translateX"] = this.prevLeft; + this.model.params["translateY"] = this.prevTop; + this.prevLeft = this.left; + this.prevTop = this.top; + break; + case TouchType.Up: + case TouchType.Cancel: + default: + break; + } + } + private model: DVModel = createDVModelFromJson( + { + compType: "Column", + children: [], + attributes: { backgroundColor: Color.Red }, + events: { onTouch: this.onTouch } + } + ); + + setOnDescendantFocusChangeListener(onFocus: () => void, onBlur: () => void) { + this.model.events["onFocus"] = onFocus; + this.model.events["onBlur"] = onBlur; + } + + public setLayoutParams(parameters: DVModelParameters): void { + if (this.model.params == null) { + this.model.params = new DVModelParameters(); + } + this.model.params['marginLeft'] = parameters['marginLeft']; + this.model.params['marginTop'] = parameters['marginTop']; + this.model.params['width'] = parameters['width']; + this.model.params['height'] = parameters['height']; + this.left = parameters['marginLeft']; + this.top = parameters['marginTop']; + } + + public addDvModel(model: DVModel): void { + this.model.children.push(model); + } + + public readyToDisplay(mutatorsStack: FlutterMutatorsStack, left: number, top: number, width: number, height: number) { + this.mutatorsStack = mutatorsStack; + this.left = left; + this.top = top; + let parameters = new DVModelParameters(); + parameters['marginLeft'] = left; + parameters['marginTop'] = top; + parameters['width'] = width; + parameters['height'] = height; + this.setLayoutParams(parameters); + this.dealMutators(); + } + + private dealMutators() { + let paths = this.mutatorsStack.getFinalClippingPaths(); + let rects = this.mutatorsStack.getFinalClippingRects(); + let matrix = this.mutatorsStack.getFinalMatrix(); + if (!paths.isEmpty()) { + let path = paths.getLast(); + this.model.params["pathWidth"] = path.width; + this.model.params["pathHeight"] = path.height; + this.model.params["pathCommands"] = path.commands; + } + if (!rects.isEmpty()) { + let rect = rects.getLast(); + this.model.params["rectWidth"] = rect.width; + this.model.params["rectHeight"] = rect.height; + this.model.params["rectRadius"] = rect.radius; + } + this.model.params["matrix"] = matrix; + } + + public getDvModel(): DVModel { + return this.model; + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/mutatorsstack/FlutterMutatorsStack.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/mutatorsstack/FlutterMutatorsStack.ets new file mode 100644 index 0000000000000000000000000000000000000000..59da6edd6c86a74b2db936777ee43ba1df117a69 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/mutatorsstack/FlutterMutatorsStack.ets @@ -0,0 +1,136 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 matrix4 from '@ohos.matrix4' +import List from '@ohos.util.List'; + +export enum FlutterMutatorType { + CLIP_RECT, + CLIP_PATH, + TRANSFORM, + OPACITY +} + +class Rect { + width: number; + height: number; + radius?: string | number | Array; + + constructor(width:number, height:number, radius?:string | number | Array) { + this.width = width; + this.height = height; + this.radius = radius; + } +} + +class Path { + width: number | string; + height: number | string; + commands?: string; + + constructor(width:number | string, height:number | string, commands?:string) { + this.width = width; + this.height = height; + this.commands = commands; + } +} + +export class FlutterMutator { + private matrix: matrix4.Matrix4Transit; + private rect: Rect; + private path: Path; + + constructor(args: matrix4.Matrix4Transit | Rect | Path) { + if (args instanceof Rect) { + this.rect = args; + } else if (args instanceof Path) { + this.path = args; + } else { + this.matrix = args; + } + } + + public getMatrix() { + return this.matrix; + } + + public getRect() { + return this.rect; + } + + public getPath() { + return this.path; + } +} + +export class FlutterMutatorsStack { + private mutators: List; + private finalClippingPaths: List; + private finalClippingRects: List; + + private finalMatrix: matrix4.Matrix4Transit; + + constructor() { + this.mutators = new List(); + this.finalClippingPaths = new List(); + this.finalClippingRects = new List(); + this.finalMatrix = matrix4.identity(); + } + + public pushTransform(values: Array): void { + if (values.length != 16) { + return; + } + let index = 0; + let matrix = matrix4.init( + [values[index++], values[index++], values[index++], values[index++], + values[index++], values[index++], values[index++], values[index++], + values[index++], values[index++], values[index++], values[index++], + values[index++], values[index++], values[index++], values[index++]]); + let mutator = new FlutterMutator(matrix); + this.mutators.add(mutator); + this.finalMatrix.combine(matrix); + } + + public pushClipRect(width:number, height:number, radius?:number) { + let rect = new Rect(width, height, radius); + let mutator = new FlutterMutator(rect); + this.mutators.add(mutator); + this.finalClippingRects.add(rect); + } + + public pushClipPath(width:number, height:number, command?:string) { + let path = new Path(width, height, command); + let mutator = new FlutterMutator(path); + this.mutators.add(mutator); + this.finalClippingPaths.add(path); + } + + public getMutators() { + return this.mutators; + } + + public getFinalClippingPaths() { + return this.finalClippingPaths; + } + + public getFinalClippingRects() { + return this.finalClippingRects; + } + + public getFinalMatrix() { + return this.finalMatrix; + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/FlutterPlugin.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/FlutterPlugin.ets similarity index 92% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/FlutterPlugin.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/FlutterPlugin.ets index 7651dee5eebade3d41debc7df9cba82cd5c1f734..3045e2b8d7ddf48a11d96a642650c63a3f6c0025 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/FlutterPlugin.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/FlutterPlugin.ets @@ -15,6 +15,7 @@ import common from '@ohos.app.ability.common'; import { BinaryMessenger } from '../../../plugin/common/BinaryMessenger'; +import PlatformViewRegistry from '../../../plugin/platform/PlatformViewRegistry'; import FlutterEngineGroup from '../FlutterEngineGroup'; export interface FlutterPlugin { @@ -50,12 +51,14 @@ export class FlutterPluginBinding { private binaryMessenger: BinaryMessenger; private flutterAssets: FlutterAssets; private group: FlutterEngineGroup; + private platformViewRegistry: PlatformViewRegistry; - constructor(applicationContext: common.Context, binaryMessenger: BinaryMessenger, flutterAssets: FlutterAssets, group: FlutterEngineGroup) { + constructor(applicationContext: common.Context, binaryMessenger: BinaryMessenger, flutterAssets: FlutterAssets, group: FlutterEngineGroup, platformViewRegistry?: PlatformViewRegistry) { this.applicationContext = applicationContext; this.binaryMessenger = binaryMessenger; this.flutterAssets = flutterAssets; this.group = group; + this.platformViewRegistry = platformViewRegistry; } getApplicationContext(): common.Context { @@ -73,6 +76,10 @@ export class FlutterPluginBinding { getEngineGroup(): FlutterEngineGroup { return this.group; } + + public getPlatformViewRegistry(): PlatformViewRegistry { + return this.platformViewRegistry; + } } /** Provides Flutter plugins with access to Flutter asset information. */ diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/PluginRegistry.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/PluginRegistry.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/PluginRegistry.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/PluginRegistry.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityAware.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityAware.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityAware.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityAware.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityControlSurface.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityControlSurface.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityControlSurface.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityControlSurface.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityPluginBinding.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityPluginBinding.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityPluginBinding.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityPluginBinding.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/renderer/FlutterUiDisplayListener.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/renderer/FlutterUiDisplayListener.ets new file mode 100644 index 0000000000000000000000000000000000000000..2a0af4009cafd2cf5229f082a41ed2d445c69caa --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/renderer/FlutterUiDisplayListener.ets @@ -0,0 +1,20 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 interface FlutterUiDisplayListener { + onFlutterUiDisplayed(): void; + + onFlutterUiNoLongerDisplayed(): void; +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/AccessibilityChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/AccessibilityChannel.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/AccessibilityChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/AccessibilityChannel.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/KeyEventChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/KeyEventChannel.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/KeyEventChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/KeyEventChannel.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/LifecycleChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/LifecycleChannel.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/LifecycleChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/LifecycleChannel.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/LocalizationChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/LocalizationChannel.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/LocalizationChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/LocalizationChannel.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/MouseCursorChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/MouseCursorChannel.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/MouseCursorChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/MouseCursorChannel.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/NavigationChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/NavigationChannel.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/NavigationChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/NavigationChannel.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/PlatformChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/PlatformChannel.ets similarity index 99% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/PlatformChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/PlatformChannel.ets index 2f74564d5b8e8b30d49f06bab30aacbe48a45134..aeb7a8c5e10db2b8d45f57c28958a3a228a92593 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/PlatformChannel.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/PlatformChannel.ets @@ -43,7 +43,6 @@ export default class PlatformChannel { try { switch (method) { case "SystemSound.play": - //TODO: break; case "HapticFeedback.vibrate": try { diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/PlatformViewsChannel.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/PlatformViewsChannel.ets new file mode 100644 index 0000000000000000000000000000000000000000..7ca54bce7c98b55549de5285a3fe05bf88318cf3 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/PlatformViewsChannel.ets @@ -0,0 +1,533 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 MethodCall from '../../../plugin/common/MethodCall'; +import MethodChannel, { MethodCallHandler, MethodResult } from '../../../plugin/common/MethodChannel'; +import StandardMethodCodec from '../../../plugin/common/StandardMethodCodec'; +import { ByteBuffer } from '../../../util/ByteBuffer'; +import Log from '../../../util/Log'; +import DartExecutor from '../dart/DartExecutor'; + +const TAG = "PlatformViewsChannel"; + +export default class PlatformViewsChannel { + private channel: MethodChannel; + private handler: PlatformViewsHandler; + + /** + * Constructs a {@code PlatformViewsChannel} that connects Android to the Dart code running in + * {@code dartExecutor}. + * + *

The given {@code dartExecutor} is permitted to be idle or executing code. + * + *

See {@link DartExecutor}. + */ + constructor(dartExecutor: DartExecutor) { + this.channel = new MethodChannel(dartExecutor, "flutter/platform_views", StandardMethodCodec.INSTANCE); + this.channel.setMethodCallHandler(this.parsingHandler); + } + + /** + * Sets the {@link PlatformViewsHandler} which receives all events and requests that are parsed + * from the underlying platform views channel. + */ + public setPlatformViewsHandler(handler: PlatformViewsHandler): void { + this.handler = handler; + } + + public invokeViewFocused(viewId: number): void { + if (this.channel == null) { + return; + } + this.channel.invokeMethod("viewFocused", viewId); + } + + private parsingHandler: MethodCallHandler = { + onMethodCall: (call: MethodCall, result: MethodResult): void => { + if (this.handler == null) { + return; + } + + Log.i(TAG, "Received '" + call.method + "' message."); + switch (call.method) { + case "create": { + this.create(call, result); + break; + } + case "dispose": { + this.dispose(call, result); + break; + } + case "resize": { + this.resize(call, result); + break; + } + case "offset": { + this.offset(call, result); + break; + } + case "touch": { + this.touch(call, result); + break; + } + case "setDirection": { + this.setDirection(call, result); + break; + } + case "clearFocus": { + this.clearFocus(call, result); + break; + } + case "synchronizeToNativeViewHierarchy": { + this.synchronizeToNativeViewHierarchy(call, result); + break; + } + default: + result.notImplemented(); + } + } + } + + create(call: MethodCall, result: MethodResult): void { + const createArgs: Map = call.args; + const usesPlatformViewLayer: boolean = createArgs.has("hybrid") && createArgs.get("hybrid") as boolean; + const additionalParams: ByteBuffer = createArgs.has("params") ? createArgs.get("params") : null; + + let direction: Direction = Direction.Ltr; + if (createArgs.get("direction") == 0) { + direction = Direction.Ltr; + } else if (createArgs.get("direction") == 1) { + direction = Direction.Rtl; + } + + Log.i(TAG, "Enter create " + usesPlatformViewLayer + " " + createArgs.get("direction") + createArgs.get("viewType")); + try { + if (usesPlatformViewLayer) { + const request: PlatformViewCreationRequest = new PlatformViewCreationRequest( + createArgs.get("id"), + createArgs.get("viewType"), + 0, + 0, + 0, + 0, + direction, + additionalParams, + RequestedDisplayMode.HYBRID_ONLY + ); + this.handler.createForPlatformViewLayer(request); + result.success(null); + } else { + const hybridFallback: boolean = createArgs.has("hybridFallback") && createArgs.get("hybridFallback"); + const displayMode: RequestedDisplayMode = + hybridFallback ? RequestedDisplayMode.TEXTURE_WITH_HYBRID_FALLBACK + : RequestedDisplayMode.TEXTURE_WITH_VIRTUAL_FALLBACK; + const request: PlatformViewCreationRequest = new PlatformViewCreationRequest( + createArgs.get("id"), + createArgs.get("viewType"), + createArgs.has("top") ? createArgs.get("top") : 0.0, + createArgs.has("left") ? createArgs.get("left") : 0.0, + createArgs.get("width"), + createArgs.get("height"), + direction, + additionalParams, + displayMode + ); + const textureId = this.handler.createForTextureLayer(request); + if (textureId == PlatformViewsHandler.NON_TEXTURE_FALLBACK) { + if (!hybridFallback) { + throw new Error( + "Platform view attempted to fall back to hybrid mode when not requested."); + } + + // A fallback to hybrid mode is indicated with a null texture ID. + result.success(null); + } else { + result.success(textureId); + } + } + } catch (err) { + Log.e(TAG, "create failed" + err); + result.error("error", err, null); + } + } + + dispose(call: MethodCall, result: MethodResult): void { + const disposeArgs: Map = call.args; + const viewId: number = disposeArgs.get("id"); + try { + this.handler.dispose(viewId); + result.success(null); + } catch (err) { + Log.e(TAG, "dispose failed", err); + result.error("error", err, null); + } + } + + resize(call: MethodCall, result: MethodResult): void { + const resizeArgs: Map = call.args; + const resizeRequest: PlatformViewResizeRequest = new PlatformViewResizeRequest( + resizeArgs.get("id"), + resizeArgs.get("width"), + resizeArgs.get("height") + ); + try { + this.handler.resize(resizeRequest, { + run: (bufferSize: PlatformViewBufferSize) => { + if (bufferSize == null) { + result.error("error", "Failed to resize the platform view", null); + } else { + const response: Map = new Map(); + response.set("width", bufferSize.width); + response.set("height", bufferSize.height); + result.success(response); + } + } + }) + } catch (err) { + Log.e(TAG, "resize failed", err); + result.error("error", err, null); + } + } + + offset(call: MethodCall, result: MethodResult): void { + const offsetArgs: Map = call.args; + try { + this.handler.offset( + offsetArgs.get("id"), + offsetArgs.get("top"), + offsetArgs.get("left")); + result.success(null); + } catch (err) { + Log.e(TAG, "offset failed", err); + result.error("error", err, null); + } + } + + touch(call: MethodCall, result: MethodResult): void { + const args: Array = call.args; + let index = 0; + const touch: PlatformViewTouch = new PlatformViewTouch( + args[index++], + args[index++], + args[index++], + args[index++], + args[index++], + args[index++], + args[index++], + args[index++], + args[index++], + args[index++], + args[index++], + args[index++], + args[index++], + args[index++], + args[index++], + args[index] + ); + + try { + this.handler.onTouch(touch); + result.success(null); + } catch (err) { + Log.e(TAG, "offset failed", err); + result.error("error", err, null); + } + } + + setDirection(call: MethodCall, result: MethodResult): void { + const setDirectionArgs: Map = call.args; + const newDirectionViewId: number = setDirectionArgs.get("id"); + const direction: number = setDirectionArgs.get("direction"); + + try { + this.handler.setDirection(newDirectionViewId, direction); + result.success(null); + } catch (err) { + Log.e(TAG, "setDirection failed", err); + result.error("error", err, null); + } + } + + clearFocus(call: MethodCall, result: MethodResult): void { + const viewId: number = call.args; + try { + this.handler.clearFocus(viewId); + result.success(null); + } catch (err) { + Log.e(TAG, "clearFocus failed", err); + result.error("error", err, null); + } + } + + synchronizeToNativeViewHierarchy(call: MethodCall, result: MethodResult): void { + const yes: boolean = call.args; + try { + this.handler.synchronizeToNativeViewHierarchy(yes); + result.success(null); + } catch (err) { + Log.e(TAG, "synchronizeToNativeViewHierarchy failed", err); + result.error("error", err, null); + } + } +} + +/** + * Handler that receives platform view messages sent from Flutter to Ohos through a given + * {@link PlatformViewsChannel}. + * + *

To register a {@code PlatformViewsHandler} with a {@link PlatformViewsChannel}, see {@link + * PlatformViewsChannel#setPlatformViewsHandler(PlatformViewsHandler)}. + */ +export abstract class PlatformViewsHandler { + /* + * The ID returned by {@code createForTextureLayer} to indicate that the requested texture mode + * was not available and the view creation fell back to {@code PlatformViewLayer} mode. + * + * This can only be returned if the {@link PlatformViewCreationRequest} sets + * {@code TEXTURE_WITH_HYBRID_FALLBACK} as the requested display mode. + */ + public static NON_TEXTURE_FALLBACK = -2; + + /** + * The Flutter application would like to display a new Ohos {@code View}, i.e., platform + * view. + * + *

The Ohos View is added to the view hierarchy. This view is rendered in the Flutter + * framework by a PlatformViewLayer. + * + * @param request The metadata sent from the framework. + */ + abstract createForPlatformViewLayer(request: PlatformViewCreationRequest): void; + + /** + * The Flutter application would like to display a new Android {@code View}, i.e., platform + * view. + * + *

The Android View is added to the view hierarchy. This view is rendered in the Flutter + * framework by a TextureLayer. + * + * @param request The metadata sent from the framework. + * @return The texture ID. + */ + abstract createForTextureLayer(request: PlatformViewCreationRequest): number; + + /** The Flutter application would like to dispose of an existing Android {@code View}. */ + abstract dispose(viewId: number): void; + + /** + * The Flutter application would like to resize an existing Android {@code View}. + * + * @param request The request to resize the platform view. + * @param onComplete Once the resize is completed, this is the handler to notify the size of the + * platform view buffer. + */ + abstract resize(request: PlatformViewResizeRequest, onComplete: PlatformViewBufferResized): void; + + /** + * The Flutter application would like to change the offset of an existing Android {@code View}. + */ + abstract offset(viewId: number, top: number, left: number): void; + + /** + * The user touched a platform view within Flutter. + * + *

Touch data is reported in {@code touch}. + */ + abstract onTouch(touch: PlatformViewTouch): void; + + /** + * The Flutter application would like to change the layout direction of an existing Android + * {@code View}, i.e., platform view. + */ + abstract setDirection(viewId: number, direction: number): void; + + /** Clears the focus from the platform view with a give id if it is currently focused. */ + abstract clearFocus(viewId: number): void; + + /** + * Whether the render surface of {@code FlutterView} should be converted to a {@code + * FlutterImageView} when a {@code PlatformView} is added. + * + *

This is done to syncronize the rendering of the PlatformView and the FlutterView. Defaults + * to true. + */ + abstract synchronizeToNativeViewHierarchy(yes: boolean): void; +} + +/** Platform view display modes that can be requested at creation time. */ +enum RequestedDisplayMode { + /** Use Texture Layer if possible, falling back to Virtual Display if not. */ + TEXTURE_WITH_VIRTUAL_FALLBACK, + /** Use Texture Layer if possible, falling back to Hybrid Composition if not. */ + TEXTURE_WITH_HYBRID_FALLBACK, + /** Use Hybrid Composition in all cases. */ + HYBRID_ONLY, +} + +/** Request sent from Flutter to create a new platform view. */ +export class PlatformViewCreationRequest { + /** The ID of the platform view as seen by the Flutter side. */ + public viewId: number; + + /** The type of view to create for this platform view. */ + public viewType: string; + + /** The density independent width to display the platform view. */ + public logicalWidth: number; + + /** The density independent height to display the platform view. */ + public logicalHeight: number; + + /** The density independent top position to display the platform view. */ + public logicalTop: number; + + /** The density independent left position to display the platform view. */ + public logicalLeft: number; + + /** + * The layout direction of the new platform view. + */ + public direction: number; + public displayMode: RequestedDisplayMode; + + /** Custom parameters that are unique to the desired platform view. */ + public params: ByteBuffer; + + constructor(viewId: number, viewType: string, logicalTop: number, logicalLeft: number, logicalWidth: number, + logicalHeight: number, direction: Direction, params: ByteBuffer, displayMode?: RequestedDisplayMode) { + this.viewId = viewId; + this.viewType = viewType; + this.logicalTop = logicalTop; + this.logicalLeft = logicalLeft; + this.logicalWidth = logicalWidth; + this.logicalHeight = logicalHeight; + this.direction = direction; + this.displayMode = displayMode ? displayMode : RequestedDisplayMode.TEXTURE_WITH_VIRTUAL_FALLBACK; + this.params = params; + } +} + +/** Request sent from Flutter to resize a platform view. */ +export class PlatformViewResizeRequest { + /** The ID of the platform view as seen by the Flutter side. */ + public viewId: number; + + /** The new density independent width to display the platform view. */ + public newLogicalWidth: number; + + /** The new density independent height to display the platform view. */ + public newLogicalHeight: number; + + constructor(viewId: number, newLogicalWidth: number, newLogicalHeight: number) { + this.viewId = viewId; + this.newLogicalWidth = newLogicalWidth; + this.newLogicalHeight = newLogicalHeight; + } +} + +/** The platform view buffer size. */ +export class PlatformViewBufferSize { + /** The width of the screen buffer. */ + public width: number; + + /** The height of the screen buffer. */ + public height: number; + + constructor(width: number, height: number) { + this.width = width; + this.height = height; + } +} + +/** Allows to notify when a platform view buffer has been resized. */ +export abstract class PlatformViewBufferResized { + abstract run(bufferSize: PlatformViewBufferSize): void; +} + +/** The state of a touch event in Flutter within a platform view. */ +export class PlatformViewTouch { + /** The ID of the platform view as seen by the Flutter side. */ + public viewId: number; + + /** The amount of time that the touch has been pressed. */ + public downTime: number; + + public eventTime: number; + + public action: number; + + /** The number of pointers (e.g, fingers) involved in the touch event. */ + public pointerCount: number; + + /** Properties for each pointer, encoded in a raw format. */ + public rawPointerPropertiesList: any; + + /** Coordinates for each pointer, encoded in a raw format. */ + public rawPointerCoords: any; + + public metaState: number; + + public buttonState: number; + + /** Coordinate precision along the x-axis. */ + public xPrecision: number; + + /** Coordinate precision along the y-axis. */ + public yPrecision: number; + + public deviceId: number; + + public edgeFlags: number; + + public source: number; + + public flags: number; + + public motionEventId: number; + + constructor(viewId: number, + downTime: number, + eventTime: number, + action: number, + pointerCount: number, + rawPointerPropertiesList: any, + rawPointerCoords: any, + metaState: number, + buttonState: number, + xPrecision: number, + yPrecision: number, + deviceId: number, + edgeFlags: number, + source: number, + flags: number, + motionEventId: number) { + this.viewId = viewId; + this.downTime = downTime; + this.eventTime = eventTime; + this.action = action; + this.pointerCount = pointerCount; + this.rawPointerPropertiesList = rawPointerPropertiesList; + this.rawPointerCoords = rawPointerCoords; + this.metaState = metaState; + this.buttonState = buttonState; + this.xPrecision = xPrecision; + this.yPrecision = yPrecision; + this.deviceId = deviceId; + this.edgeFlags = edgeFlags; + this.source = source; + this.flags = flags; + this.motionEventId = motionEventId; + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/RestorationChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/RestorationChannel.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/RestorationChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/RestorationChannel.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/SettingsChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/SettingsChannel.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/SettingsChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/SettingsChannel.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/SystemChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/SystemChannel.ets similarity index 95% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/SystemChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/SystemChannel.ets index 1c92edc71810feda0241d4d250a46a428d80eb49..ded2507910ccd6a4837c290948e42ef5c158c9e0 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/SystemChannel.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/SystemChannel.ets @@ -20,7 +20,7 @@ import DartExecutor from '../dart/DartExecutor'; const TAG: string = "SystemChannel"; /** - * TODO(mattcarroll): fill in javadoc for SystemChannel. + * fill in javadoc for SystemChannel. */ export default class SystemChannel { public channel: BasicMessageChannel; diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TestChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TestChannel.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TestChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TestChannel.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ets similarity index 99% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ets index 225439d1fdbb76d324f8c0df0b051dccd9e56a0b..5c80c6c580951e631a834ea243869a04e38edf79 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ets @@ -194,7 +194,6 @@ export class Configuration { inputType:InputType; inputAction: Number; actionLabel: String; - //TODO: Autofill autofill; contentCommitMimeTypes: String[]; fields: Configuration[]; diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/ExclusiveAppComponent.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/ExclusiveAppComponent.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/ExclusiveAppComponent.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/ExclusiveAppComponent.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets similarity index 92% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets index efd35e82ba17b1aada5f8803c611019717c0810e..dd91f3697268be1ddbaddab2f0d861bf0db6c90c 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbility.ets @@ -26,7 +26,11 @@ import display from '@ohos.display'; import { FlutterPlugin } from '../engine/plugins/FlutterPlugin'; import { AsyncCallback } from '@ohos.base'; import AbilityConstant from '@ohos.app.ability.AbilityConstant'; - +import I18n from '@ohos.i18n' +import { PlatformBrightness } from '../engine/systemchannels/SettingsChannel'; +import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant'; +import { DVModelContainer } from '../../view/DynamicView/dynamicView'; +import { RootDvModeManager } from '../../plugin/platform/RootDvModelManager'; const TAG = "FlutterAbility"; /** @@ -42,7 +46,6 @@ export class FlutterAbility extends UIAbility implements Host { private viewportMetrics = new ViewportMetrics(); private displayInfo: display.Display; - /** * onCreate * 1、create and attach delegate @@ -55,6 +58,7 @@ export class FlutterAbility extends UIAbility implements Host { globalThis.flutterAbility = this this.displayInfo = display.getDefaultDisplaySync() this.viewportMetrics.devicePixelRatio = this.displayInfo.densityPixels + this.delegate = new FlutterAbilityDelegate(this); await this.delegate.onAttach(this.context); Log.i(TAG, 'onAttach end'); @@ -65,6 +69,9 @@ export class FlutterAbility extends UIAbility implements Host { if (this.stillAttachedForEvent("onCreate")) { this.delegate.onCreate(); } + + console.log('MyAbility onCreate'); + globalThis.applicationContext = this.context.getApplicationContext(); } onDestroy() { @@ -77,7 +84,7 @@ export class FlutterAbility extends UIAbility implements Host { * window状态改变回调 * @param windowStage */ - onWindowStageCreate(windowStage: window.WindowStage) { + async onWindowStageCreate(windowStage: window.WindowStage) { this.windowStage = windowStage try { windowStage.on('windowStageEvent', (data) => { @@ -119,7 +126,8 @@ export class FlutterAbility extends UIAbility implements Host { this.onWindowPropertiesUpdated(); }); - this.loadContent() + this.loadContent(); + this.mainWindow.setWindowLayoutFullScreen(true); } catch (exception) { Log.e(TAG, 'Failed to enable the listener for window stage event changes. Cause:' + JSON.stringify(exception)); } @@ -245,7 +253,6 @@ export class FlutterAbility extends UIAbility implements Host { } getDartEntrypointLibraryUri(): string { - // TODO form metaData read return null; } @@ -257,7 +264,6 @@ export class FlutterAbility extends UIAbility implements Host { if (this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_DART_ENTRYPOINT]) { return this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_DART_ENTRYPOINT] as string; } - // TODO form metaData read return FlutterAbilityLaunchConfigs.DEFAULT_DART_ENTRYPOINT } @@ -265,7 +271,6 @@ export class FlutterAbility extends UIAbility implements Host { if (this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_INITIAL_ROUTE]) { return this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_INITIAL_ROUTE] as string; } - // TODO form metaData read return null } @@ -274,7 +279,6 @@ export class FlutterAbility extends UIAbility implements Host { } shouldDestroyEngineWithHost(): boolean { - //TODO shouldDestroyEngineWithHost return true; } @@ -361,6 +365,14 @@ export class FlutterAbility extends UIAbility implements Host { } } + onConfigurationUpdated(config){ + Log.i(TAG, 'onConfigurationUpdated config:' + JSON.stringify(config)); + this.delegate.flutterEngine.getSettingsChannel().startMessage() + .setAlwaysUse24HourFormat(I18n.System.is24HourClock()) + .setPlatformBrightness(config.colorMode != ConfigurationConstant.ColorMode.COLOR_MODE_DARK + ? PlatformBrightness.LIGHT : PlatformBrightness.DARK); + } + getWindowId(callback: AsyncCallback): void { if (callback === null) { return; @@ -381,7 +393,7 @@ export class FlutterAbility extends UIAbility implements Host { } } -class ViewportMetrics { +export class ViewportMetrics { devicePixelRatio: number = 1.0; physicalWidth: number = 0; physicalHeight: number = 0; diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityDelegate.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityDelegate.ets similarity index 99% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityDelegate.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityDelegate.ets index 8325e3eb58db19f6296b4944dab0de292d7143c0..57944bd721a3cfb05d1683ed2d07267cabd67d1b 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityDelegate.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityDelegate.ets @@ -44,7 +44,7 @@ const PLUGINS_RESTORATION_BUNDLE_KEY = "plugins"; */ class FlutterAbilityDelegate implements ExclusiveAppComponent { private host: Host; - private flutterEngine: FlutterEngine; + flutterEngine: FlutterEngine; platformPlugin: PlatformPlugin; private context: common.Context; private textInputPlugin: TextInputPlugin; @@ -222,7 +222,6 @@ class FlutterAbilityDelegate implements ExclusiveAppComponent { } onDetach() { - //todo if (this.host.shouldAttachEngineToActivity()) { // Notify plugins that they are no longer attached to an Activity. Log.d(TAG, "Detaching FlutterEngine from the Ability"); @@ -352,7 +351,6 @@ class FlutterAbilityDelegate implements ExclusiveAppComponent { onSaveState(reason: AbilityConstant.StateType, wantParam: { [key: string]: Object; }): AbilityConstant.OnSaveResult { Log.i(TAG, "onSaveInstanceState. Giving framework and plugins an opportunity to save state."); this.ensureAlive(); - // TODO shouldRestoreAndSaveState if (this.host.shouldAttachEngineToActivity()) { const plugins = {} const result = this.flutterEngine.getAbilityControlSurface().onSaveState(reason, plugins); diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityLaunchConfigs.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityLaunchConfigs.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityLaunchConfigs.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityLaunchConfigs.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterEngineConfigurator.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterEngineConfigurator.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterEngineConfigurator.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterEngineConfigurator.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterEngineProvider.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterEngineProvider.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterEngineProvider.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterEngineProvider.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets index d6a123491dabc58c13e5b83d26381da81ff328bb..3e5993c068f95829235476210a739091866d3fcb 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets @@ -12,23 +12,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { PlatformViewWrapper } from '../../plugin/platform/PlatformViewWrapper'; +import { RootDvModeManager } from '../../plugin/platform/RootDvModelManager'; +import { DVModel, + DVModelChildren, + DVModelContainer, + DVModelEvents, + DVModelParameters, DynamicView } from '../../view/DynamicView/dynamicView'; +import { createDVModelFromJson } from '../../view/DynamicView/dynamicViewJson'; /** * 基础page组件,承载XComponent组件 */ @Component export struct FlutterPage { - @State message: string = 'Hello World' - private context = null; + @State message: string = 'Hello World'; + + @State rootDvModel: DVModelContainer = RootDvModeManager.getRootDvMode(); build() { - Column() { - XComponent({ id: 'flutterXComponent', type: 'texture', libraryname: 'flutter' }) - .onLoad((context) => { - this.context = context; - }) - .onDestroy(() => { - }) - } + DynamicView({ + model: this.rootDvModel.model as DVModel, + params: this.rootDvModel.model.params as DVModelParameters, + events: this.rootDvModel.model.events as DVModelEvents, + children: this.rootDvModel.model.children as DVModelChildren, + customBuilder: this.rootDvModel.model.builder as ($$: { params: DVModelParameters }) => void + }) } } \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/OhosTouchProcessor.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/OhosTouchProcessor.ets new file mode 100644 index 0000000000000000000000000000000000000000..1c6d907c3afc5ca1a8363cb1440e76fa5b7e4769 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/OhosTouchProcessor.ets @@ -0,0 +1,58 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 { TouchEvent } from '@ohos.multimodalInput.touchEvent'; + +export default class OhosTouchProcessor { + private static POINTER_DATA_FIELD_COUNT: number = 35; + + static BYTES_PER_FIELD: number = 8; + + private static POINTER_DATA_FLAG_BATCHED: number = 1; + + public onTouchEvent(event: TouchEvent, transformMatrix: any): void { + + } +} + +export enum PointerChange { + CANCEL = 0, + ADD = 1, + REMOVE = 2, + HOVER = 3, + DOWN = 4, + MOVE = 5, + UP = 6, + PAN_ZOOM_START = 7, + PAN_ZOOM_UPDATE = 8, + PAN_ZOOM_END = 9 +} + +export enum PointerDeviceKind { + TOUCH = 0, + MOUSE = 1, + STYLUS = 2, + INVERTED_STYLUS = 3, + TRACKPAD = 4, + UNKNOWN = 5 +} + +export enum PointerSignalKind { + NONE = 0, + SCROLL = 1, + SCROLL_INERTIA_CANCEL = 2, + SCALE = 3, + UNKNOWN = 4 +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/Settings.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/Settings.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/Settings.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/Settings.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/TouchEventTracker.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/TouchEventTracker.ets new file mode 100644 index 0000000000000000000000000000000000000000..fb4d9b69fd47d5edc6df56e81b8c2ddd5b4c62b4 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/TouchEventTracker.ets @@ -0,0 +1,88 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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. +*/ + +/** Tracks the motion events received by the FlutterView. */ +import PlainArray from '@ohos.util.PlainArray'; +import { TouchEvent } from '@ohos.multimodalInput.touchEvent'; +import Queue from '@ohos.util.Queue'; + +export class TouchEventTracker { + private eventById : PlainArray; + private unusedEvents : Queue; + private static INSTANCE:TouchEventTracker; + + public static getInstance() : TouchEventTracker { + if (this.INSTANCE == null) { + this.INSTANCE = new TouchEventTracker(); + } + return this.INSTANCE; + } + + constructor() { + this.eventById = new PlainArray(); + this.unusedEvents = new Queue(); + } + + /** Tracks the event and returns a unique MotionEventId identifying the event. */ + public track(event :TouchEvent) : TouchEventId { + const eventId:TouchEventId = TouchEventId.createUnique(); + this.eventById.add(eventId.getId(), event); + this.unusedEvents.add(eventId.getId()); + return eventId; + } + + /** + * Returns the MotionEvent corresponding to the eventId while discarding all the motion events + * that occurred prior to the event represented by the eventId. Returns null if this event was + * popped or discarded. + */ + public pop(eventId : TouchEventId) : TouchEvent { + // remove all the older events. + while (this.unusedEvents.length != 0 && this.unusedEvents.getFirst() < eventId.getId()) { + this.eventById.remove(this.unusedEvents.pop()); + } + + // remove the current event from the heap if it exists. + if (this.unusedEvents.length != 0 && this.unusedEvents.getFirst() == eventId.getId()) { + this.unusedEvents.pop(); + } + + const event : TouchEvent = this.eventById.get(eventId.getId()); + this.eventById.remove(eventId.getId()); + return event; + } +} + +/** Represents a unique identifier corresponding to a motion event. */ +export class TouchEventId { + private static ID_COUNTER : number = 0; + private id : number; + + constructor(id : number) { + this.id = id; + } + + public static from(id : number) : TouchEventId { + return new TouchEventId(id); + } + + public static createUnique() : TouchEventId { + return new TouchEventId(this.ID_COUNTER++); + } + + public getId() : number { + return this.id; + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/WindowInfoRepositoryCallbackAdapterWrapper.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/WindowInfoRepositoryCallbackAdapterWrapper.ets new file mode 100644 index 0000000000000000000000000000000000000000..ae2c6cfd5202c3f2c912720217df452a727f35b6 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/WindowInfoRepositoryCallbackAdapterWrapper.ets @@ -0,0 +1,23 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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'; + +export default class WindowInfoRepositoryCallbackAdapterWrapper { + + constructor() { + } + +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/PlatformPlugin.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/PlatformPlugin.ets similarity index 98% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/PlatformPlugin.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/PlatformPlugin.ets index c05992dc51e9156a9c498abf01d69a333d8a16b6..826408b9a5476ee365d1604b6f54837f1d0f1c8f 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/PlatformPlugin.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/PlatformPlugin.ets @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import PlatformChannel, { AppSwitcherDescription, Brightness, @@ -98,7 +99,6 @@ export default class PlatformPlugin { }, setApplicationSwitcherDescription:(description: AppSwitcherDescription): void => { - //TODO:The Flutter application would like to be displayed in app switcher with the visual // representation described in the given {@code description}. }, @@ -276,8 +276,6 @@ export default class PlatformPlugin { } setSystemChromeChangeListener(): void { - //TODO: Set up a listener to notify the framework when the system ui has changed. - // if(this.callbackId == null && this.applicationContext != null) { let that = this; this.callbackId = this.applicationContext.on('environment',{ diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BasicMessageChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BasicMessageChannel.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BasicMessageChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BasicMessageChannel.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BinaryCodec.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BinaryCodec.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BinaryCodec.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BinaryCodec.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BinaryMessenger.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BinaryMessenger.ets similarity index 98% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BinaryMessenger.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BinaryMessenger.ets index 91476c16720e0aafa195c4053039e14b0a23e763..87c91df70bf51b5135403710ab7ce3bd6616428f 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BinaryMessenger.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/BinaryMessenger.ets @@ -131,7 +131,6 @@ export abstract class BinaryMessenger { */ //setMessageHandler(channel: String, handler: BinaryMessageHandler) setMessageHandler(channel: String, handler: BinaryMessageHandler, taskQueue?: TaskQueue): void { - // TODO(92582): Remove default implementation when it is safe for Google Flutter users. if (taskQueue != null) { throw new Error("setMessageHandler called with nonnull taskQueue is not supported.") } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/EventChannel.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/EventChannel.ets new file mode 100644 index 0000000000000000000000000000000000000000..fcf725cf922e452cc2af843bf73c2d70a3a180f1 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/EventChannel.ets @@ -0,0 +1,263 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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. +*/ + + +/** + * A named channel for communicating with the Flutter application using asynchronous event streams. + * + *

Incoming requests for event stream setup are decoded from binary on receipt, and Java + * responses and events are encoded into binary before being transmitted back to Flutter. The {@link + * MethodCodec} used must be compatible with the one used by the Flutter application. This can be + * achieved by creating an EventChannel + * counterpart of this channel on the Dart side. The Java type of stream configuration arguments, + * events, and error details is {@code Object}, but only values supported by the specified {@link + * MethodCodec} can be used. + * + *

The logical identity of the channel is given by its name. Identically named channels will + * interfere with each other's communication. + */ +import Log from '../../util/Log'; +import { BinaryMessageHandler, BinaryMessenger, BinaryReply, TaskQueue } from './BinaryMessenger'; +import MethodCodec from './MethodCodec'; +import StandardMethodCodec from './StandardMethodCodec'; + +const TAG = "EventChannel#"; + +export default class EventChannel { + private messenger: BinaryMessenger; + private name: string; + private codec: MethodCodec; + private taskQueue: TaskQueue; + + constructor(messenger: BinaryMessenger, name: string, codec?: MethodCodec, taskQueue?: TaskQueue) { + this.messenger = messenger + this.name = name + this.codec = codec ? codec : StandardMethodCodec.INSTANCE + this.taskQueue = taskQueue + } + + + /** + * Registers a stream handler on this channel. + * + *

Overrides any existing handler registration for (the name of) this channel. + * + *

If no handler has been registered, any incoming stream setup requests will be handled + * silently by providing an empty stream. + * + * @param handler a {@link StreamHandler}, or null to deregister. + */ + setStreamHandler(handler: StreamHandler): void { + // We call the 2 parameter variant specifically to avoid breaking changes in + // mock verify calls. + // See https://github.com/flutter/flutter/issues/92582. + if (this.taskQueue != null) { + this.messenger.setMessageHandler( + this.name, handler == null ? null : new IncomingStreamRequestHandler(handler, this.name, this.codec, this.messenger), this.taskQueue); + } else { + this.messenger.setMessageHandler( + this.name, handler == null ? null : new IncomingStreamRequestHandler(handler, this.name, this.codec, this.messenger)); + } + } +} + +/** + * Handler of stream setup and teardown requests. + * + *

Implementations must be prepared to accept sequences of alternating calls to {@link + * #onListen(Object, EventChannel.EventSink)} and {@link #onCancel(Object)}. Implementations + * should ideally consume no resources when the last such call is not {@code onListen}. In typical + * situations, this means that the implementation should register itself with platform-specific + * event sources {@code onListen} and deregister again {@code onCancel}. + */ +export interface StreamHandler { + /** + * Handles a request to set up an event stream. + * + *

Any uncaught exception thrown by this method will be caught by the channel implementation + * and logged. An error result message will be sent back to Flutter. + * + * @param arguments stream configuration arguments, possibly null. + * @param events an {@link EventSink} for emitting events to the Flutter receiver. + */ + onListen(args: any, events: EventSink): void; + + /** + * Handles a request to tear down the most recently created event stream. + * + *

Any uncaught exception thrown by this method will be caught by the channel implementation + * and logged. An error result message will be sent back to Flutter. + * + *

The channel implementation may call this method with null arguments to separate a pair of + * two consecutive set up requests. Such request pairs may occur during Flutter hot restart. Any + * uncaught exception thrown in this situation will be logged without notifying Flutter. + * + * @param arguments stream configuration arguments, possibly null. + */ + onCancel(args: any): void; +} + +/** + * Event callback. Supports dual use: Producers of events to be sent to Flutter act as clients of + * this interface for sending events. Consumers of events sent from Flutter implement this + * interface for handling received events (the latter facility has not been implemented yet). + */ +export interface EventSink { + /** + * Consumes a successful event. + * + * @param event the event, possibly null. + */ + success(event: any): void; + + /** + * Consumes an error event. + * + * @param errorCode an error code String. + * @param errorMessage a human-readable error message String, possibly null. + * @param errorDetails error details, possibly null + */ + error(errorCode: string, errorMessage: string, errorDetails: any): void; + + /** + * Consumes end of stream. Ensuing calls to {@link #success(Object)} or {@link #error(String, + * String, Object)}, if any, are ignored. + */ + endOfStream(): void; +} + +class IncomingStreamRequestHandler implements BinaryMessageHandler { + private handler: StreamHandler; + private activeSink = new AtomicReference(null); + private codec: MethodCodec; + private name: string; + private messenger: BinaryMessenger; + + constructor(handler: StreamHandler, name: string, codec: MethodCodec, messenger: BinaryMessenger) { + this.handler = handler; + this.codec = codec; + this.name = name; + this.messenger = messenger; + } + + onMessage(message: ArrayBuffer, reply: BinaryReply): void { + const call = this.codec.decodeMethodCall(message); + if (call.method == "listen") { + this.onListen(call.args, reply); + } else if (call.method == "cancel") { + this.onCancel(call.args, reply); + } else { + reply.reply(null); + } + } + + onListen(args: any, callback: BinaryReply): void { + const eventSink = new EventSinkImplementation(this.activeSink, this.name, this.codec, this.messenger); + const oldSink = this.activeSink.getAndSet(eventSink); + if (oldSink != null) { + // Repeated calls to onListen may happen during hot restart. + // We separate them with a call to onCancel. + try { + this.handler.onCancel(null); + } catch (e) { + Log.e(TAG + this.name, "Failed to close existing event stream", e); + } + } + try { + this.handler.onListen(args, eventSink); + callback.reply(this.codec.encodeSuccessEnvelope(null)); + } catch (e) { + this.activeSink.set(null); + Log.e(TAG + this.name, "Failed to open event stream", e); + callback.reply(this.codec.encodeErrorEnvelope("error", e.getMessage(), null)); + } + } + + onCancel(args: any, callback: BinaryReply): void { + const oldSink = this.activeSink.getAndSet(null); + if (oldSink != null) { + try { + this.handler.onCancel(args); + callback.reply(this.codec.encodeSuccessEnvelope(null)); + } catch (e) { + Log.e(TAG + this.name, "Failed to close event stream", e); + callback.reply(this.codec.encodeErrorEnvelope("error", e.getMessage(), null)); + } + } else { + callback.reply(this.codec.encodeErrorEnvelope("error", "No active stream to cancel", null)); + } + } +} + +class EventSinkImplementation implements EventSink { + private hasEnded = false; + private activeSink: AtomicReference; + private messenger: BinaryMessenger; + private codec: MethodCodec; + private name: string; + + constructor(activeSink: AtomicReference, name: string, codec: MethodCodec, messenger: BinaryMessenger) { + this.activeSink = activeSink; + this.codec = codec; + this.name = name; + this.messenger = messenger; + } + + success(event: any): void { + if (this.hasEnded || this.activeSink.get() != this) { + return; + } + this.messenger.send(this.name, this.codec.encodeSuccessEnvelope(event)); + } + + error(errorCode: string, errorMessage: string, errorDetails: any) { + if (this.hasEnded || this.activeSink.get() != this) { + return; + } + this.messenger.send( + this.name, this.codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails)); + } + + endOfStream(): void { + if (this.hasEnded || this.activeSink.get() != this) { + return; + } + this.hasEnded = true; + this.messenger.send(this.name, null); + } +} + +class AtomicReference { + private value: T; + + constructor(value: T) { + this.value = value + } + + get(): T { + return this.value; + } + + set(newValue: T): void { + this.value = newValue; + } + + getAndSet(newValue: T) { + const oldValue = this.value; + this.value = newValue; + return oldValue; + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/FlutterException.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/FlutterException.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/FlutterException.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/FlutterException.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/JSONMessageCodec.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/JSONMessageCodec.ets similarity index 83% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/JSONMessageCodec.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/JSONMessageCodec.ets index 7d1167dd0eab9ccda4a64526d1816725a288d346..bf6576f49658ee8845e4d8aa208e6f1fae7edda5 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/JSONMessageCodec.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/JSONMessageCodec.ets @@ -14,16 +14,15 @@ */ import MessageCodec from './MessageCodec'; +import MethodCodec from './MethodCodec'; import StringCodec from './StringCodec'; /** - * A {@link MessageCodec} using UTF-8 encoded JSON messages. + * A {@link MethodCodec} using UTF-8 encoded JSON method calls and result envelopes. * *

This codec is guaranteed to be compatible with the corresponding JSONMessageCodec - * on the Dart side. These parts of the Flutter SDK are evolved synchronously. - * - *

Supports the same Java values as {@link JSONObject#wrap(Object)}. + * href="https://api.flutter.dev/flutter/services/JSONMethodCodec-class.html">JSONMethodCodec on + * the Dart side. These parts of the Flutter SDK are evolved synchronously. * *

On the Dart side, JSON messages are handled by the JSON facilities of the dart:convert package. diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/JSONMethodCodec.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/JSONMethodCodec.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/JSONMethodCodec.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/JSONMethodCodec.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MessageCodec.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MessageCodec.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MessageCodec.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MessageCodec.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodCall.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodCall.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodCall.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodCall.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodChannel.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodChannel.ets similarity index 97% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodChannel.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodChannel.ets index 3f91fbc6cb5261691ab98d869497e2cdb46c4655..e6ae8800e74a7ce3f21a381289b93ed493ac6998 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodChannel.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodChannel.ets @@ -18,6 +18,7 @@ import MessageChannelUtils from '../../util/MessageChannelUtils'; import { BinaryMessageHandler, BinaryMessenger, BinaryReply, TaskQueue } from './BinaryMessenger'; import MethodCall from './MethodCall'; import MethodCodec from './MethodCodec'; +import StandardMethodCodec from './StandardMethodCodec'; /** * A named channel for communicating with the Flutter application using asynchronous method calls. * @@ -39,7 +40,7 @@ export default class MethodChannel { private codec: MethodCodec; private taskQueue: TaskQueue; - constructor(messenger: BinaryMessenger, name: string, codec?: MethodCodec, taskQueue?: TaskQueue) { + constructor(messenger: BinaryMessenger, name: string, codec: MethodCodec = StandardMethodCodec.INSTANCE, taskQueue?: TaskQueue) { this.messenger = messenger this.name = name this.codec = codec diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodCodec.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodCodec.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodCodec.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/MethodCodec.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/PluginRegistry.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/PluginRegistry.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/PluginRegistry.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/PluginRegistry.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/StandardMessageCodec.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/StandardMessageCodec.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/StandardMessageCodec.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/StandardMessageCodec.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/StandardMethodCodec.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/StandardMethodCodec.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/StandardMethodCodec.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/StandardMethodCodec.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/StringCodec.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/StringCodec.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/StringCodec.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/common/StringCodec.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/ListenableEditingState.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/ListenableEditingState.ets similarity index 99% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/ListenableEditingState.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/ListenableEditingState.ets index 87f50bf489855dfd0bb2d3bfa770f4dfb3c18a62..72735c0a29a1e893e8bf986458cea0da82df0d2b 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/ListenableEditingState.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/ListenableEditingState.ets @@ -143,7 +143,6 @@ export class ListenableEditingState { this.setSelectionStart(0); this.setSelectionEnd(0); } - //TODO: setComposingRange(state.composingStart,state.composingEnd); this.endBatchEdit(); } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextEditingDelta.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextEditingDelta.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextEditingDelta.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextEditingDelta.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ets similarity index 99% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ets index a8441dffa51b8883544af204a0d629913da91a7e..33d5cda317dbf2e6d952f452b61244949d5083f0 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ets @@ -27,7 +27,6 @@ export default class TextInputPlugin implements EditingStateWatcher{ private inputMethodController: inputMethod.InputMethodController; private inputTarget: InputTarget; private configuration: Configuration; - //TODO:private autofillConfiguration: private mEditable: ListenableEditingState; private mRestartInputPending: boolean; diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/localization/LocalizationPlugin.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/localization/LocalizationPlugin.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/localization/LocalizationPlugin.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/localization/LocalizationPlugin.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/mouse/MouseCursorPlugin.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/mouse/MouseCursorPlugin.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/mouse/MouseCursorPlugin.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/mouse/MouseCursorPlugin.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/AccessibilityEventsDelegate.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/AccessibilityEventsDelegate.ets new file mode 100644 index 0000000000000000000000000000000000000000..faa3bc90e50c304744883689a532d0dc323bd714 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/AccessibilityEventsDelegate.ets @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 AccessibilityBridge from '../../view/AccessibilityBridge'; + +export class AccessibilityEventsDelegate { + private accessibilityBridge: AccessibilityBridge; + + requestSendAccessibilityEvent(accessibilityBridge: AccessibilityBridge): boolean { + if (accessibilityBridge == null) { + return false; + } + return true; + } + + onAccessibilityHoverEvent(accessibilityBridge: AccessibilityBridge): boolean { + if (accessibilityBridge == null) { + return false; + } + return true; + } + + setAccessibilityBridge (accessibilityBridge: AccessibilityBridge): void { + this.accessibilityBridge = accessibilityBridge; + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformOverlayView.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformOverlayView.ets new file mode 100644 index 0000000000000000000000000000000000000000..2f156cdcd2c3ca95128738e20e8ffb863f772264 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformOverlayView.ets @@ -0,0 +1,28 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 { AccessibilityEventsDelegate } from './AccessibilityEventsDelegate'; + +export class PlatformOverlayView { + private accessibilityEventsDelegate: AccessibilityEventsDelegate; + // @ts-ignore + constructor(context: Context, width: Number, height: Number, accessibilityEventsDelegate: AccessibilityEventsDelegate) { + this.accessibilityEventsDelegate= accessibilityEventsDelegate; + } + + public onHoverEvent(): boolean { + return false; + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformView.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformView.ets new file mode 100644 index 0000000000000000000000000000000000000000..ddf5f59a71c4d1c7d51082bcf104990e0faa08c6 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformView.ets @@ -0,0 +1,80 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 { DVModel, DynamicView } from '../../view/DynamicView/dynamicView' + +/** A handle to an DynamicView to be embedded in the Flutter hierarchy. */ +export default abstract class PlatformView { + /** Returns the DynamicView to be embedded in the Flutter hierarchy. */ + abstract getView(): DVModel; + + /** + * Called by the {@link io.flutter.embedding.engine.FlutterEngine} that owns this {@code + * PlatformView} when the DynamicView responsible for rendering a Flutter UI is + * associated with the {@link io.flutter.embedding.engine.FlutterEngine}. + * + *

This means that our associated {@link io.flutter.embedding.engine.FlutterEngine} can now + * render a UI and interact with the user. + * + *

Some platform views may have unusual dependencies on the {@link View} that renders Flutter + * UIs, such as unique keyboard interactions. That {@link View} is provided here for those + * purposes. Use of this {@link View} should be avoided if it is not absolutely necessary, because + * depending on this {@link View} will tend to make platform view code more brittle to future + * changes. + */ + onFlutterViewAttached(dvModel: DVModel): void {} + + /** + * Called by the {@link io.flutter.embedding.engine.FlutterEngine} that owns this {@code + * PlatformView} when the DynamicView responsible for rendering a Flutter UI is detached + * and disassociated from the {@link io.flutter.embedding.engine.FlutterEngine}. + * + *

This means that our associated {@link io.flutter.embedding.engine.FlutterEngine} no longer + * has a rendering surface, or a user interaction surface of any kind. + * + *

This platform view must release any references related to the DynamicView that was + * provided in {@link #onFlutterViewAttached(View)}. + */ + onFlutterViewDetached(): void {} + + /** + * Dispose this platform view. + * + *

The {@link PlatformView} object is unusable after this method is called. + * + *

Plugins implementing {@link PlatformView} must clear all references to the View object and + * the PlatformView after this method is called. Failing to do so will result in a memory leak. + * + *

References related to the DynamicView attached in {@link + * #onFlutterViewAttached(View)} must be released in {@code dispose()} to avoid memory leaks. + */ + abstract dispose(): void; + + /** + * Callback fired when the platform's input connection is locked, or should be used. + * + *

This hook only exists for rare cases where the plugin relies on the state of the input + * connection. This probably doesn't need to be implemented. + */ + onInputConnectionLocked(): void {} + + /** + * Callback fired when the platform input connection has been unlocked. + * + *

This hook only exists for rare cases where the plugin relies on the state of the input + * connection. This probably doesn't need to be implemented. + */ + onInputConnectionUnlocked(): void {} +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewFactory.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewFactory.ets new file mode 100644 index 0000000000000000000000000000000000000000..fe96017e0031f91706636d5f574e5eedf0d3c23e --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewFactory.ets @@ -0,0 +1,44 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 MessageCodec from '../common/MessageCodec'; +import PlatformView from './PlatformView' +import common from '@ohos.app.ability.common'; + +export default abstract class PlatformViewFactory { + private createArgsCodec: MessageCodec; + + /** @param createArgsCodec the codec used to decode the args parameter of {@link #create}. */ + constructor(createArgsCodec: MessageCodec) { + this.createArgsCodec = createArgsCodec; + } + + /** + * Creates a new Dynamic be embedded in the Flutter hierarchy. + * + * @param context the context to be used when creating the view, this is different than + * FlutterView's context. + * @param viewId unique identifier for the created instance, this value is known on the Dart side. + * @param args arguments sent from the Flutter app. The bytes for this value are decoded using the + * createArgsCodec argument passed to the constructor. This is null if createArgsCodec was + * null, or no arguments were sent from the Flutter app. + */ + public abstract create(context: common.Context, viewId: number, args: any): PlatformView; + + /** Returns the codec to be used for decoding the args parameter of {@link #create}. */ + getCreateArgsCodec(): MessageCodec { + return this.createArgsCodec; + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewRegistry.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewRegistry.ets new file mode 100644 index 0000000000000000000000000000000000000000..2c49f5eeaddb54cece120df8eea307c69ad76ebf --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewRegistry.ets @@ -0,0 +1,32 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 PlatformViewFactory from './PlatformViewFactory' + +/** + * Registry for platform view factories. + * + *

Plugins can register factories for specific view types. + */ +export default interface PlatformViewRegistry { + /** + * Registers a factory for a platform view. + * + * @param viewTypeId unique identifier for the platform view's type. + * @param factory factory for creating platform views of the specified type. + * @return true if succeeded, false if a factory is already registered for viewTypeId. + */ + registerViewFactory(viewTypeId: string, factory: PlatformViewFactory): boolean; +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewRegistryImpl.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewRegistryImpl.ets new file mode 100644 index 0000000000000000000000000000000000000000..98cb247d890cbe65150feb84242c01128047e7f9 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewRegistryImpl.ets @@ -0,0 +1,40 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 HashMap from '@ohos.util.HashMap'; +import PlatformViewFactory from './PlatformViewFactory' +import PlatformViewRegistry from './PlatformViewRegistry' + +export default class PlatformViewRegistryImpl implements PlatformViewRegistry { + // Maps a platform view type id to its factory. + private viewFactories: HashMap; + + constructor() { + this.viewFactories = new HashMap(); + } + + registerViewFactory(viewTypeId: string, factory: PlatformViewFactory): boolean { + if (this.viewFactories.hasKey(viewTypeId)) { + return false; + } + + this.viewFactories.set(viewTypeId, factory); + return true; + } + + getFactory(viewTypeId: string): PlatformViewFactory { + return this.viewFactories.get(viewTypeId); + } +} diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewWrapper.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewWrapper.ets new file mode 100644 index 0000000000000000000000000000000000000000..e49d0fd33a6c046d7cbe6242388f7e4816ed5ed1 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewWrapper.ets @@ -0,0 +1,87 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 OhosTouchProcessor from '../../embedding/ohos/OhosTouchProcessor'; +import { DVModel, DVModelParameters } from '../../view/DynamicView/dynamicView'; +import { createDVModelFromJson } from '../../view/DynamicView/dynamicViewJson'; +import { RootDvModeManager } from './RootDvModelManager'; +import matrix4 from '@ohos.matrix4' +import Log from '../../util/Log'; + +const TAG: string = "PlatformViewWrapper"; +export class PlatformViewWrapper { + private prevLeft: number; + private prevTop: number; + private left: number; + private top: number; + private bufferWidth: number; + private bufferHeight: number; + private touchProcessor: OhosTouchProcessor; + + private onTouch = (touchEvent) => { + switch (touchEvent.type) { + case TouchType.Down: + this.prevLeft = this.left; + this.prevTop = this.top; + this.model.params["translateX"] = this.left; + this.model.params["translateY"] = this.top; + break; + case TouchType.Move: + this.model.params["translateX"] = this.prevLeft; + this.model.params["translateY"] = this.prevTop; + this.prevLeft = this.left; + this.prevTop = this.top; + break; + case TouchType.Up: + case TouchType.Cancel: + default: + break; + } + } + + private model : DVModel = createDVModelFromJson( + { + compType: "Column", + children: [], + attributes: {backgroundColor: Color.Red}, + events: {onTouch : this.onTouch} + } + ); + + public setTouchProcessor(newTouchProcessor: OhosTouchProcessor): void { + this.touchProcessor = newTouchProcessor; + } + + constructor() { + } + + public getDvModel(): DVModel { + return this.model; + } + + public setLayoutParams(parameters : DVModelParameters): void { + if (this.model.params == null) { + this.model.params = new DVModelParameters(); + } + this.model.params['marginLeft'] = parameters['marginLeft']; + this.model.params['marginTop'] = parameters['marginTop']; + this.left = parameters['marginLeft']; + this.top = parameters['marginTop']; + } + + public addDvModel(model: DVModel): void { + this.model.children.push(model); + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewsAccessibilityDelegate.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewsAccessibilityDelegate.ets new file mode 100644 index 0000000000000000000000000000000000000000..10efaea68661361f4af0e22e873b62f0b798bb4d --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewsAccessibilityDelegate.ets @@ -0,0 +1,43 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 AccessibilityBridge from '../../view/AccessibilityBridge'; + +export interface PlatformViewsAccessibilityDelegate { + /** + * Returns the root of the view hierarchy for the platform view with the requested id, or null if + * there is no corresponding view. + */ + getPlatformViewById(viewId: number): any; + + /** Returns true if the platform view uses virtual displays. */ + usesVirtualDisplay(id: number): boolean; + + /** + * Attaches an accessibility bridge for this platform views accessibility delegate. + * + *

Accessibility events originating in platform views belonging to this delegate will be + * delegated to this accessibility bridge. + */ + attachAccessibilityBridge(accessibilityBridge: AccessibilityBridge): void; + + /** + * Detaches the current accessibility bridge. + * + *

Any accessibility events sent by platform views belonging to this delegate will be ignored + * until a new accessibility bridge is attached. + */ + detachAccessibilityBridge(): void; +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewsController.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewsController.ets new file mode 100644 index 0000000000000000000000000000000000000000..9d8fa2dcb428f01a8d71ba70298a17bef5cf33c9 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/PlatformViewsController.ets @@ -0,0 +1,479 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 { PlatformViewsAccessibilityDelegate } from './PlatformViewsAccessibilityDelegate'; +import PlatformViewsChannel, { + PlatformViewBufferResized, + PlatformViewCreationRequest, + PlatformViewResizeRequest, + PlatformViewsHandler, PlatformViewTouch, PlatformViewBufferSize +} from '../../../ets/embedding/engine/systemchannels/PlatformViewsChannel'; +import PlatformView from './PlatformView'; +import { DVModel, DVModelParameters, DynamicView } from '../../view/DynamicView/dynamicView'; +import display from '@ohos.display'; +import { FlutterView } from '../../view/FlutterView'; +import { TextureRegistry } from '../../view/TextureRegistry'; +import TextInputPlugin from '../editing/TextInputPlugin'; +import { PlatformOverlayView } from './PlatformOverlayView'; +import { PlatformViewWrapper } from './PlatformViewWrapper'; +import { FlutterOverlaySurface } from '../../embedding/engine/FlutterOverlaySurface'; +import HashSet from '@ohos.util.HashSet'; +import PlatformViewRegistry from './PlatformViewRegistry'; +import PlatformViewRegistryImpl from './PlatformViewRegistryImpl'; +import DartExecutor from '../../embedding/engine/dart/DartExecutor'; +import { AccessibilityEventsDelegate } from './AccessibilityEventsDelegate'; +import AccessibilityBridge from '../../view/AccessibilityBridge'; +import { RootDvModeManager } from './RootDvModelManager'; +import { FlutterMutatorView } from '../../embedding/engine/mutatorsstack/FlutterMutatorView'; +import common from '@ohos.app.ability.common'; +import Log from '../../util/Log' +import OhosTouchProcessor from '../../embedding/ohos/OhosTouchProcessor' +import PlatformViewFactory from './PlatformViewFactory' +import { ByteBuffer } from '../../util/ByteBuffer'; + +const TAG = "PlatformViewsController" + +export default class PlatformViewsController implements PlatformViewsAccessibilityDelegate, PlatformViewsHandler { + private registry: PlatformViewRegistryImpl; + private context: Context; + private flutterView: FlutterView; + private textureRegistry: TextureRegistry; + private textInputPlugin: TextInputPlugin; + private platformViewsChannel: PlatformViewsChannel; + private accessibilityEventsDelegate: AccessibilityEventsDelegate; + private nextOverlayLayerId: number = 0; + private ohosTouchProcessor: OhosTouchProcessor; + private usesSoftwareRendering: boolean = false; + + private platformViews: Map; + private overlayLayerViews: Map; + private viewWrappers: Map; + private currentFrameUsedOverlayLayerIds: HashSet; + private currentFrameUsedPlatformViewIds: HashSet; + private rootDvModel = RootDvModeManager.getRootDvMode(); + private platformViewParent: Map; + + constructor() { + this.registry = new PlatformViewRegistryImpl(); + this.accessibilityEventsDelegate = new AccessibilityEventsDelegate(); + this.overlayLayerViews = new Map(); + this.currentFrameUsedOverlayLayerIds = new HashSet(); + this.currentFrameUsedPlatformViewIds = new HashSet(); + this.viewWrappers = new Map(); + this.platformViews = new Map(); + this.platformViewParent = new Map(); + } + + getPlatformViewById(viewId: number) { + throw new Error('Method not implemented.'); + } + + usesVirtualDisplay(id: number): boolean { + throw new Error('Method not implemented.'); + } + + attachAccessibilityBridge(accessibilityBridge: AccessibilityBridge): void { + throw new Error('Method not implemented.'); + } + + detachAccessibilityBridge(): void { + throw new Error('Method not implemented.'); + } + + createForPlatformViewLayer(request: PlatformViewCreationRequest): void { + Log.i(TAG, "Enter createForPlatformViewLayer"); + this.ensureValidRequest(request); + + let platformView: PlatformView = this.createPlatformView(request, false); + + this.configureForHybridComposition(platformView, request); + } + + dispose(viewId: number): void { + let platformView: PlatformView = this.platformViews.get(viewId); + if (platformView == null) { + Log.e(TAG, "Disposing unknown platform view with id: " + viewId); + return; + } + this.platformViews.delete(viewId); + + try { + platformView.dispose(); + } catch (err) { + Log.e(TAG, "Disposing platform view threw an exception", err); + } + + let viewWrapper: PlatformViewWrapper = this.viewWrappers.get(viewId); + if (viewWrapper != null) { + this.viewWrappers.delete(viewId); + } + + let parentView: FlutterMutatorView = this.platformViewParent.get(viewId); + if (parentView != null) { + this.platformViewParent.delete(viewId); + } + } + + resize(request: PlatformViewResizeRequest, onComplete: PlatformViewBufferResized): void { + let physicalWidth: number = this.toPhysicalPixels(request.newLogicalWidth); + let physicalHeight: number = this.toPhysicalPixels(request.newLogicalHeight); + let viewId: number = request.viewId; + Log.i(TAG, `Resize viewId ${viewId}, pw:${physicalWidth}, ph:${physicalHeight},lw:${request.newLogicalWidth}, lh:${request.newLogicalHeight}`); + + let platformView: PlatformView = this.platformViews.get(viewId); + let viewWrapper: PlatformViewWrapper = this.viewWrappers.get(viewId); + if (platformView == null || viewWrapper == null) { + Log.e(TAG, "Resizing unknown platform view with id: " + viewId); + return; + } + + let viewWrapperLayoutParams: DVModelParameters = viewWrapper.getDvModel().getLayoutParams(); + if (physicalWidth) { + viewWrapperLayoutParams["width"] = physicalWidth; + } + + if (physicalHeight) { + viewWrapperLayoutParams["height"] = physicalHeight; + } + + let embeddedView: DVModel = platformView.getView(); + if (embeddedView != null) { + let embeddedViewLayoutParams = embeddedView.getLayoutParams(); + if (physicalWidth) { + embeddedViewLayoutParams["width"] = physicalWidth; + } + + if (physicalHeight) { + embeddedViewLayoutParams["height"] = physicalHeight; + } + } + } + + offset(viewId: number, top: number, left: number): void { + Log.i(TAG, `Offset is id${viewId}, t:${top}, l:${left}`); + let viewWrapper: PlatformViewWrapper = this.viewWrappers.get(viewId); + if (viewWrapper == null) { + Log.e(TAG, "Setting offset for an unknown platform view with id: " + viewId); + return; + } + + let physicalTop = this.toPhysicalPixels(top); + let physicalLeft = this.toPhysicalPixels(left); + let params = viewWrapper.getDvModel().params; + params["marginTop"] = physicalTop; + params["marginLeft"] = physicalLeft; + viewWrapper.setLayoutParams(params); + } + + onTouch(touch: PlatformViewTouch): void { + let viewId: number = touch.viewId; + let density: number = display.getDefaultDisplaySync().densityDPI; + + let platformView: PlatformView = this.platformViews.get(viewId); + if (platformView == null) { + Log.e(TAG, "Sending touch to an unknown platform view with id: " + viewId); + return; + } + let dvModel: DVModel = platformView.getView(); + if (dvModel == null) { + Log.e(TAG, "Sending touch to a null dv model with id: " + viewId); + } + Log.e(TAG, "Sending touch to a dv model with id: " + viewId.toString()); + sendEventByKey(viewId.toString(), 10, ""); + } + + setDirection(viewId: number, direction: number): void { + if (!this.validateDirection(direction)) { + throw new Error("Trying to set unknown direction value: " + + direction + + "(view id: " + + viewId + + ")"); + } + + const platformView = this.platformViews.get(viewId); + if (platformView == null) { + Log.e(TAG, "Setting direction to an unknown view with id: " + viewId); + return; + } + const embeddedView = platformView.getView(); + if (embeddedView == null) { + Log.e(TAG, "Setting direction to a null view with id: " + viewId); + return; + } + embeddedView.params["direction"] = direction; + } + + validateDirection(direction:number):boolean { + return direction == Direction.Ltr || direction == Direction.Rtl || direction == Direction.Auto; + } + + clearFocus(viewId: number): void { + const platformView = this.platformViews.get(viewId); + if (platformView == null) { + Log.e(TAG, "Setting direction to an unknown view with id: " + viewId); + return; + } + const embeddedView = platformView.getView(); + if (embeddedView == null) { + Log.e(TAG, "Setting direction to a null view with id: " + viewId); + return; + } + focusControl.requestFocus("flutterXComponent"); + } + synchronizeToNativeViewHierarchy(yes: boolean): void { + throw new Error('Method not implemented.'); + } + + public createForTextureLayer(request: PlatformViewCreationRequest): number { + Log.i(TAG, "Enter createForTextureLayer"); + this.ensureValidRequest(request); + + let viewId: number = request.viewId; + if (this.viewWrappers.get(request.viewId) != null) { + throw new Error( + "Trying to create an already created platform view, view id: " + viewId); + } + + let platformView: PlatformView = this.createPlatformView(request, true); + let dynamicView: DVModel = platformView.getView(); + return this.configureForTextureLayerComposition(platformView, request); + } + + private ensureValidRequest(request: PlatformViewCreationRequest): void { + if (!this.validateDirection(request.direction)) { + throw new Error("Trying to create a view with unknown direction value: " + + request.direction + + "(view id: " + + request.viewId + + ")") + } + } + + private createPlatformView(request: PlatformViewCreationRequest, wrapContext: boolean): PlatformView { + Log.i(TAG, "Enter createPlatformView"); + const viewFactory: PlatformViewFactory = this.registry.getFactory(request.viewType); + if (viewFactory == null) { + throw new Error("Trying to create a platform view of unregistered type: " + request.viewType) + } + + let createParams: any = null; + if (request.params != null) { + let byteParas : ByteBuffer = request.params as ByteBuffer; + createParams = viewFactory.getCreateArgsCodec().decodeMessage(byteParas.buffer); + } + + let mutableContext: common.Context = this.context; + let platformView = viewFactory.create(mutableContext, request.viewId, createParams); + + let embeddedView: DVModel = platformView.getView(); + if (embeddedView == null) { + throw new Error("PlatformView#getView() returned null, but an dynamic view reference was expected."); + } + + embeddedView.params['direction'] = request.direction; + + this.platformViews.set(request.viewId, platformView); + return platformView; + } + + // Configures the view for Hybrid Composition mode. + private configureForHybridComposition(platformView: PlatformView, request: PlatformViewCreationRequest): void { + Log.i(TAG, "Using hybrid composition for platform view: " + request.viewId); + } + + private configureForTextureLayerComposition(platformView: PlatformView, request: PlatformViewCreationRequest): number { + Log.i(TAG, "Hosting view in view hierarchy for platform view: " + request.viewId); + + let viewWrapper: PlatformViewWrapper = new PlatformViewWrapper(); + let textureId: number = 0; + + let physicalTop: number = this.toPhysicalPixels(request.logicalTop); + let physicalLeft: number = this.toPhysicalPixels(request.logicalLeft); + + Log.i(TAG, `View pW:${request.logicalWidth}, pH:${request.logicalHeight}, pT:${physicalTop}, pL:${physicalLeft}`); + + let param: DVModelParameters = new DVModelParameters(); + param['marginLeft'] = physicalLeft; + param['marginTop'] = physicalTop; + + let model = platformView.getView(); + if (request.logicalWidth != null) { + let physicalWidth: number = this.toPhysicalPixels(request.logicalWidth); + model.params['width'] = physicalWidth; + param['width'] = physicalWidth; + } + + if (request.logicalHeight != null) { + let physicalHeight: number = this.toPhysicalPixels(request.logicalHeight); + model.params['height'] = physicalHeight; + param['height'] = physicalHeight; + } + + viewWrapper.setLayoutParams(param); + viewWrapper.addDvModel(model); + + RootDvModeManager.addDvModel(viewWrapper.getDvModel()); + this.viewWrappers.set(request.viewId, viewWrapper); + Log.i(TAG, "Create platform view success"); + + return textureId; + } + + public attach(context: Context, textureRegistry: TextureRegistry, dartExecutor: DartExecutor): void { + if (this.context != null) { + + } + this.context = context; + this.textureRegistry = textureRegistry; + this.platformViewsChannel = new PlatformViewsChannel(dartExecutor); + this.platformViewsChannel.setPlatformViewsHandler(this); + } + + public detach(): void { + if (this.platformViewsChannel != null) { + this.platformViewsChannel.setPlatformViewsHandler(null); + } + this.destroyOverlaySurfaces(); + this.platformViewsChannel = null; + this.context = null; + this.textureRegistry = null; + } + + public attachToView() { + for (let wrapper of this.viewWrappers.values()) { + this.rootDvModel.model.children.push(wrapper.getDvModel()); + } + for (let mutator of this.platformViewParent.values()) { + this.rootDvModel.model.children.push(mutator.getDvModel()); + } + for (let platformView of this.platformViews.values()) { + platformView.onFlutterViewAttached(this.rootDvModel.model); + } + } + + public detachFromView(): void { + for (let index = 0; index < this.viewWrappers.size; index++) { + this.rootDvModel.model.children.pop(); + } + for (let index = 0; index < this.platformViewParent.size; index++) { + this.rootDvModel.model.children.pop(); + } + this.destroyOverlaySurfaces(); + this.removeOverlaySurfaces(); + this.rootDvModel = null; + + for (let platformView of this.platformViews.values()) { + platformView.onFlutterViewDetached(); + } + } + + public attachTextInputPlugin(textInputPlugin: TextInputPlugin): void { + this.textInputPlugin = textInputPlugin; + } + + public detachTextInputPlugin(): void { + this.textInputPlugin == null; + } + + public getRegistry(): PlatformViewRegistry { + return this.registry; + } + + public onDetachedFromNapi(): void { + this.diposeAllViews(); + } + + public onPreEngineRestart(): void { + this.diposeAllViews(); + } + + private getDisplayDensity(): number { + return display.getDefaultDisplaySync().densityPixels; + } + private toPhysicalPixels(logicalPixels: number): number { + return Math.round(px2vp(logicalPixels * this.getDisplayDensity())); + } + + private toLogicalPixelsByDensity(physicalPixels: number, displayDensity: number): number { + return Math.round(physicalPixels / displayDensity); + } + + private toLogicalPixels(physicalPixels: number): number { + return this.toLogicalPixelsByDensity(physicalPixels, this.getDisplayDensity()); + } + + + private diposeAllViews(): void { + } + + private initializeRootImageViewIfNeeded(): void { + } + + initializePlatformViewIfNeeded(viewId: number): void { + let platformView: PlatformView = this.platformViews[viewId]; + if (platformView == null) { + throw new Error("Platform view hasn't been initialized from the platform view channel."); + } + if (this.platformViewParent[viewId] == null) { + return; + } + let dvModel: DVModel = platformView.getView(); + if (dvModel == null) { + throw new Error("PlatformView#getView() returned null, but an ohos dv model reference was expected."); + } + let parentView: FlutterMutatorView = new FlutterMutatorView(); + parentView.setOnDescendantFocusChangeListener(() => { + this.platformViewsChannel.invokeViewFocused(viewId); + }, () => { + if (this.textInputPlugin != null) { + this.textInputPlugin.clearTextInputClient(); + } + }); + } + + public onDisplayOverlaySurface(id: number, x: number, y: number, width: number, height: number): void { + } + + public onBeginFrame(): void { + this.currentFrameUsedOverlayLayerIds.clear(); + this.currentFrameUsedPlatformViewIds.clear(); + } + + public onEndFrame(): void { + } + + private finishFrame(isFrameRenderedUsingImageReaders: boolean): void { + } + + public createOverlaySurfaceByPlatformOverlayView(imageView: PlatformOverlayView) { + let id = this.nextOverlayLayerId++; + this.overlayLayerViews.set(id, imageView); + return new FlutterOverlaySurface(this.nextOverlayLayerId++); + } + + public createOverlaySurface(): FlutterOverlaySurface { + return new FlutterOverlaySurface(this.nextOverlayLayerId++); + } + + private destroyOverlaySurfaces(): void { + } + + private removeOverlaySurfaces(): void { + if (!(this.flutterView instanceof FlutterView)) { + return; + } + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/RootDvModelManager.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/RootDvModelManager.ets new file mode 100644 index 0000000000000000000000000000000000000000..3b3a43bb3a9cf5a5d678dc361a145a387711e5d7 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/platform/RootDvModelManager.ets @@ -0,0 +1,63 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 { DVModel, + DVModelContainer, + DVModelParameters } from '../../view/DynamicView/dynamicView'; +import { createDVModelFromJson } from '../../view/DynamicView/dynamicViewJson'; + +@Component +struct XComponentStruct { + private context; + + build() { + XComponent({ id: 'flutterXComponent', type: 'texture', libraryname: 'flutter' }) + .onLoad((context) => { + this.context = context; + }) + .onDestroy(() => { + }) + } +} + +@Builder function BuildXComponentStruct($$: {param: DVModelParameters}) { + XComponentStruct(); +} + +export class RootDvModeManager { + private static xComponentModel = + { + compType: "xComponent", + build: BuildXComponentStruct + }; + + private static model : DVModel = createDVModelFromJson( + { + compType: "Stack", + children: [RootDvModeManager.xComponentModel], + attributes: {alignContent: Alignment.TopStart}, + } + ); + + private static container : DVModelContainer = new DVModelContainer(RootDvModeManager.model); + + public static getRootDvMode(): DVModelContainer { + return RootDvModeManager.container; + } + + public static addDvModel(model: DVModel): void { + RootDvModeManager.container.model.children.push(model); + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/ByteBuffer.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/ByteBuffer.ets similarity index 99% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/ByteBuffer.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/ByteBuffer.ets index 2a809ad8542c8ad9e2511159753df686daa34b30..5eed99c13c05d0ccd96368b08742dafa45a74456 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/ByteBuffer.ts +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/ByteBuffer.ets @@ -772,7 +772,6 @@ export class ByteBuffer { * @returns The byte length. */ setString(byteOffset: number, value: string, byteEncoding?: string, write?: boolean): number { - // TODO: add support for "utf-16-be" and "utf-16-le" if (byteEncoding && byteEncoding !== "utf-8") { throw new TypeError("String encoding '" + byteEncoding + "' is not supported") } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/Log.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/Log.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/Log.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/Log.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/MessageChannelUtils.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/MessageChannelUtils.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/MessageChannelUtils.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/MessageChannelUtils.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/PathUtils.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/PathUtils.ets new file mode 100644 index 0000000000000000000000000000000000000000..691ea0f360b40adb266bde566c2f66292a2aa0ff --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/PathUtils.ets @@ -0,0 +1,46 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 common from '@ohos.app.ability.common'; +import fs from '@ohos.file.fs'; +import Log from './Log'; + +/** + * ohos路径获取工具 + */ +const TAG: string = "PathUtils"; + +export default class PathUtils { + static getFilesDir(context: common.Context): string { + return context.filesDir; + } + + static getCacheDirectory(context: common.Context): string { + return context.cacheDir; + } + + static getDataDirectory(context: common.Context): string { + const name = "flutter"; + const flutterDir = context.filesDir + "/" + name; + if (!fs.accessSync(flutterDir)) { + try { + fs.mkdirSync(flutterDir); + } catch (err) { + Log.e(TAG, "mkdirSync failed err:" + err); + return null; + } + } + return flutterDir; + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/StringUtils.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/StringUtils.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/StringUtils.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/StringUtils.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/ToolUtils.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/ToolUtils.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/ToolUtils.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/ToolUtils.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/TraceSection.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/TraceSection.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/TraceSection.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/util/TraceSection.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/AccessibilityBridge.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/AccessibilityBridge.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/AccessibilityBridge.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/AccessibilityBridge.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/DynamicView/dynamicView.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/DynamicView/dynamicView.ets new file mode 100644 index 0000000000000000000000000000000000000000..403ce9c865c53a38a8c2d43812d3918dc1487662 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/DynamicView/dynamicView.ets @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Dynamic View creation + * from a recursive data structure + * + * exported @Component: DynamicView + * exported view model classes: + * - DVModelContainer + * - DVModel + * - DVModelParameters + * - DVModelEvents + * - DVModelChildren + * + * The purpose of exporting the DVModel classes + * is to make them available to the converter from + * JD's XML format and the expression parser. These + * components are expected to generate and update the + * DVModel. + * + * An application written by JS should only import + * DynamicView, DVModelContainer to be used in their own ArkUI + * container view. + */ + +/** + * View Model classes + */ + +@Observed +export class DVModelParameters extends Object { + /* empty, just get any instance wrapped inside an ObservedObject + with the help of the decoration */ +} + +@Observed +export class DVModelEvents extends Object { + /* empty, just get any instance wrapped inside an ObservedObject + with the help of the decoration */ +} + +@Observed +export class DVModelChildren extends Array { + /* empty, just get any instance wrapped inside an ObservedObject + with the help of the decoration */ +} + +let nextId: number = 1; + +@Observed +export class DVModel { + id_: number; + compType: string; + params: DVModelParameters; + events: DVModelEvents; + children: DVModelChildren; + builder: any; + + constructor(compType: string, params: DVModelParameters, events: DVModelEvents, children: DVModelChildren, builder?: any) { + this.id_ = nextId++; + this.compType = compType; + this.params = params ?? new DVModelParameters; + this.events = events; + this.children = children; + this.builder = builder; + } + + public getLayoutParams(): DVModelParameters { + return this.params; + } +} + +// includes the root DVModel objects. +export class DVModelContainer { + model: DVModel; + + constructor(model: DVModel) { + this.model = model; + } +} + +/** + DynamicView is the @Component that does all the work: + + The following 4 features are the key solution elements for dynamic View + construction and update: + + 1. The if statement decides which framework component to create. + We can not use a factory function here, because that would requite calling + a regular function inside build() or a @Builder function. + + 2. Take note of the @Builder for Row, Column containers: + These functions create DynamicView Views inside a DynamicView + view. This behaviour is why we talk about DynamicView as a 'recursive' View. + All @Builder functions are member functions of the DynamicView @Component to + retain access ('this.xyz') to its decorated state variables. + + 3. The @Extend functions execute attribute and event handler registration functions + for all attributes and events permissable on the framework component, irrespective + if DVModelParameters or DVModelEvents objects includes a value or not. If not + the attribute or event is set to 'undefined' by intention. This is required to unset + any previously set value. + + 4. The scope ('this') of any lambda registered as an event hander function, e.g. for onClick, + is the @Component, in which the DVModel object is initialized. This said, it is advised to initialize + the DVModel object in the @Component that is parent to outmost DynamicView. Thereby, + any event handler function is able to mutate decorated state variables of that @Component + + */ + +@Component +export struct DynamicView { + @ObjectLink model: DVModel; + @ObjectLink children: DVModelChildren; + @ObjectLink params: DVModelParameters; + @ObjectLink events: DVModelEvents; + @BuilderParam customBuilder?: ($$: { params: DVModelParameters }) => void; + + + /* + we use this @Styles member function to set all common attributes and event handlers + and set component specific attribute and event handler functions in the @Builder function + */ + @Styles common_attrs() { + .width(this.params["width"]) + .height(this.params["height"]) + .backgroundColor(this.params["backgroundColor"]) + .onClick(this.events["onClick"]) + .margin({ + left: this.params["marginLeft"], + right: this.params["marginRight"], + top: this.params["marginTop"], + bottom: this.params["marginBottom"] + }) + .onTouch(this.events["onTouch"]) + .onFocus(this.events['onFocus']) + .onBlur(this.events["onBlur"]) + .translate({ + x: this.params["translateX"], + y: this.params["translateY"], + z: this.params["translateZ"] + }) + .transform(this.params["matrix"]) + .direction(this.params["direction"]) + } + + @Styles clip_attrs() { + .clip(this.params["rectWidth"] ? new Rect({ + width: this.params["rectWidth"], + height: this.params["rectHeight"], + radius: this.params["rectRadius"] + }) : null) + .clip(this.params["pathWidth"] ? new Path({ + width: this.params["pathWidth"], + height: this.params["pathHeight"], + commands: this.params["pathCommands"] + }) : null) + } + + @Builder buildChildren() { + ForEach(this.children, + child => { + DynamicView({ + model: child as DVModel, + params: child.params, + events: child.events, + children: child.children, + customBuilder: child.builder + }) + }, + child => `${child.id_}` + ) + } + + @Builder buildRow() { + Row() { + this.buildChildren() + } + .common_attrs() + .clip_attrs() + } + + @Builder buildColumn() { + Column() { + this.buildChildren() + } + .common_attrs() + .clip_attrs() + } + + @Builder buildStack() { + Stack() { + this.buildChildren() + } + .common_attrs() + .clip_attrs() + .alignContent(this.params["alignContent"]) + } + + @Builder buildText() { + Text(`${this.params["value"]}`) + .common_attrs() + .fontColor(this.params["fontColor"]) + } + + @Builder buildImage() { + Image(this.params["src"]) + .common_attrs() + } + + // Button with label + @Builder buildButton() { + Button(this.params["value"]) + .common_attrs() + } + + @Builder buildCustom() { + if (this.customBuilder) { + this.customBuilder({ params: this.params }); + } + } + + build() { + if (this.model.compType == "Column") { + this.buildColumn() + } else if (this.model.compType == "Row") { + this.buildRow() + } else if (this.model.compType == "Stack") { + this.buildStack() + } else if (this.model.compType == "Text") { + this.buildText() + } else if (this.model.compType == "Image") { + this.buildImage() + } else if (this.model.compType == "Button") { + this.buildButton() + } else { + this.buildCustom() + } + } +} diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/DynamicView/dynamicViewJson.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/DynamicView/dynamicViewJson.ets new file mode 100644 index 0000000000000000000000000000000000000000..b398c8022244443e62f6388bbfd5dd5eb28427c0 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/DynamicView/dynamicViewJson.ets @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DVModel, DVModelParameters, DVModelEvents, DVModelChildren } from "./dynamicView"; + +export function createDVModelFromJson(json: Object): DVModel { + + /* private use helper functions */ + + function createChildrenFrom(children: Array): DVModelChildren { + let result = new DVModelChildren(); + if (Array.isArray(children)) { + (children as Array).forEach(child => { + const childView = createDVModelFromJson(child); + if (childView != undefined) { + result.push(childView); + } + }); + } + return result; + } + + function createAttributesFrom(attributes: Object): DVModelParameters { + let result = new DVModelParameters(); + if ((typeof attributes == "object") && (!Array.isArray(attributes))) { + Object.keys(attributes).forEach(k => result[k] = attributes[k]); + } + return result; + } + + function createEventsFrom(events: Object): DVModelEvents { + let result = new DVModelEvents(); + if ((typeof events == "object") && (!Array.isArray(events))) { + Object.keys(events).forEach(k => result[k] = events[k]); + } + return result; + } + + if (typeof json !== 'object') { + console.error("createDVModelFromJson: input is not JSON"); + return undefined; + } + + return new DVModel( + json["compType"], + createAttributesFrom(json["attributes"]), + createEventsFrom(json["events"]), + createChildrenFrom(json["children"]), + json["build"] + ); +} diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterCallbackInformation.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterCallbackInformation.ets similarity index 100% rename from shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterCallbackInformation.ts rename to shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterCallbackInformation.ets diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterNativeView.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterNativeView.ets new file mode 100644 index 0000000000000000000000000000000000000000..9138ad728502e49e675e69e1fd533d80ad7016bc --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterNativeView.ets @@ -0,0 +1,137 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 common from '@ohos.app.ability.common'; +import DartExecutor from '../embedding/engine/dart/DartExecutor'; +import { EngineLifecycleListener } from '../embedding/engine/FlutterEngine'; +import FlutterNapi from '../embedding/engine/FlutterNapi'; +import Log from '../util/Log'; +import FlutterPluginRegistry from '../app/FlutterPluginRegistry'; +import FlutterRunArguments from './FlutterRunArguments'; +import { FlutterView } from './FlutterView'; + +const TAG: string = "FlutterNativeView"; + +export default class FlutterNativeView { + private mContext: common.Context; + private mPluginRegistry: FlutterPluginRegistry; + private mFlutterNapi: FlutterNapi; + private dartExecutor: DartExecutor; + private mFlutterView: FlutterView; + private applicationIsRunning: boolean; + + constructor(context: common.Context, isBackgroundView?: boolean) { + if (isBackgroundView) { + Log.i(TAG, "isBackgroundView is no longer supported and will be ignored"); + } + this.mContext = context; + this.mPluginRegistry = new FlutterPluginRegistry(); + this.mFlutterNapi = new FlutterNapi(); + //this.mFlutterNapi.addIsDisplayingFlutterUiListener(this.flutterUiDisplayListener); + this.dartExecutor = new DartExecutor(this.mFlutterNapi, this.mContext.resourceManager); + this.mFlutterNapi.addEngineLifecycleListener(new EngineLifecycleListenerImpl(this.mFlutterView, this.mPluginRegistry)); + this.attach(this.mFlutterNapi, this.dartExecutor); + this.assertAttached(this.mFlutterNapi); + } + + attach(flutterNapi: FlutterNapi, dartExecutor: DartExecutor): void { + flutterNapi.attachToNative(); + dartExecutor.onAttachedToNAPI(); + } + + assertAttached(flutterNapi: FlutterNapi): void { + if (!this.isAttached(flutterNapi)) { + throw new Error('Platform View is not attached'); + } + } + + isAttached(flutterNapi: FlutterNapi): boolean { + return flutterNapi.isAttached(); + } + + detachFromFlutterView(): void { + this.mPluginRegistry.detach(); + this.mFlutterView = null; + } + + destroy(): void { + this.mPluginRegistry.destroy(); + this.dartExecutor.onDetachedFromNAPI(); + this.mFlutterView = null; + //this.mFlutterNapi.removeIsDisplayingFlutterUiListener(this.flutterUiDisplayListener); + this.applicationIsRunning = false; + } + + getDartExecutor(): DartExecutor { + return this.dartExecutor; + } + + getPluginRegistry(): FlutterPluginRegistry { + return this.mPluginRegistry; + } + + attachViewAndAbility(flutterView: FlutterView, context: common.Context): void { + this.mFlutterView = flutterView; + this.mPluginRegistry.attach(flutterView, context); + } + + runFromBundle(args: FlutterRunArguments): void { + if (args.entrypoint == null) { + throw new Error("an entrypoint must be specific"); + } + this.assertAttached(this.mFlutterNapi); + if (this.applicationIsRunning) { + throw new Error("this flutter engine instance is already running an application"); + } + this.mFlutterNapi.runBundleAndSnapshotFromLibrary(args.bundlePath, args.entrypoint, args.libraryPath, this.mContext.resourceManager, null); + this.applicationIsRunning = true; + } + + isApplicationRunning(): boolean { + return this.applicationIsRunning; + } + + // getObservatoryUri(): string { + // return this.mFlutterNapi.getObservatoryUri(); + // } +} + +class EngineLifecycleListenerImpl implements EngineLifecycleListener { + private flutterView: FlutterView; + private pluginRegistry: FlutterPluginRegistry; + + onPreEngineRestart(): void { + if (this.flutterView != null) { + //this.flutterView.resetAccessibilityTree(); + } + + if (this.pluginRegistry == null) { + return; + } + + this.pluginRegistry.onPreEngineRestart(); + } + + onEngineWillDestroy(): void { + + } + + constructor(flutterView: FlutterView, pluginRegistry: FlutterPluginRegistry) { + this.flutterView = flutterView; + this.pluginRegistry = pluginRegistry; + } +} + + diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterRunArguments.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterRunArguments.ets new file mode 100644 index 0000000000000000000000000000000000000000..d17ec28d1fdc6237ee486362751ee25e58590887 --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterRunArguments.ets @@ -0,0 +1,20 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 FlutterRunArguments { + public bundlePath: string; + public entrypoint: string; + public libraryPath: string; +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterView.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterView.ets new file mode 100644 index 0000000000000000000000000000000000000000..cf38a74159eb41c2ca4b6ede7f9e04e0cc66bf5a --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterView.ets @@ -0,0 +1,18 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 FlutterView { + +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/TextureRegistry.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/TextureRegistry.ets new file mode 100644 index 0000000000000000000000000000000000000000..a37ab971b769320021695970ff20e2cac62d880b --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/TextureRegistry.ets @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 interface TextureRegistry { + + createSurfaceTexture(): SurfaceTextureEntry; + registerSurfaceTexture(): SurfaceTextureEntry; + + onTrimMemory(level: number) : void; +} + +interface SurfaceTextureEntry { + id(): number; + + release(): void; +} + +interface OnFrameConsumedListener { + onFrameConsumed(): void; +} + +interface OnTrimMemoryListener { + onTrimMemory(level: number) : void; +} \ No newline at end of file