Commit 41843963 authored by lujie's avatar lujie
Browse files

Merge branch 'feat-demo' into 'main'

feat(app): init

See merge request !1
parents 8d522ac0 b8124cc0
import { POST_MESSAGE_TO_HOST } from '../workers/HostProxy'
export function RegisterGalleryManager() {
const register: Record<string, Object> = {};
register["GalleryManager"] = GalleryManager;
return register;
}
export class GalleryManager {
public SelectPicture(callback: (state: string, path: string, msg: string) => void, pweight: number, pheight: number,
maxSelectNumber: number, isPhotoTakingSupported: boolean) {
const param: Array<ESObject> = [pweight, pheight, maxSelectNumber, isPhotoTakingSupported]
let msg: ESObject = {
type: "RUN_ON_UI_THREAD_JS",
funcName: "GalleryHandler.GallerySelector",
args: param,
callback: callback,
timeoutMs: 100000,
}
POST_MESSAGE_TO_HOST(msg);
}
public async AddToGallery(albumName: Array<string>, callback: (params: Array<ESObject>) => void) {
const param: Array<ESObject> = [albumName]
let msg: ESObject = {
type: "RUN_ON_UI_THREAD_JS",
funcName: "GalleryHandler.AddToGallery",
args: param,
callback: callback,
timeoutMs: 100000,
}
POST_MESSAGE_TO_HOST(msg);
}
static _instance: GalleryManager;
public static getInstance(): GalleryManager {
if (GalleryManager._instance == null) {
GalleryManager._instance = new GalleryManager();
}
return GalleryManager._instance
}
}
import { TuanjieLog } from '../common/TuanjieLog';
import { REGISTER_BUILTIN_MODULE, MSG_RECEIVER } from '../workers/MessageProcessor';
export class SoftInputUtils {
public showSoftInput(initialText: string): void {
globalThis.inputInitialText = initialText;
globalThis.dialogController.open();
TuanjieLog.info("Show softInput " + initialText);
}
public hideSoftInput(): void {
globalThis.dialogController.close();
TuanjieLog.info("Hide softInput");
}
}
!!REGISTER_BUILTIN_MODULE && REGISTER_BUILTIN_MODULE(MSG_RECEIVER.HOST_UI, new SoftInputUtils());
\ No newline at end of file
import settings from '@ohos.settings';
import { GetFromGlobalThis } from '../common/GlobalThisUtil';
import { Context } from '@ohos.abilityAccessCtrl';
import { TuanjieLog } from '../common/TuanjieLog';
import connection from '@ohos.bluetooth.connection';
import { BusinessError } from '@ohos.base';
import { REGISTER_BUILTIN_MODULE, MSG_RECEIVER } from '../workers/MessageProcessor';
export class SystemSettings {
isAutoRotationLocked(): boolean {
let context: Context = GetFromGlobalThis('AbilityContext');
if (context == null || context == undefined) {
TuanjieLog.warn('can not get context from globalThis');
return true;
}
return settings.getValueSync(context, settings.general.ACCELEROMETER_ROTATION_STATUS, '0') === '0';
}
getDeviceName(): string {
try {
let localName: string = connection.getLocalName();
return localName == "" ? "<unknown>" :localName;
} catch (err) {
console.error('failed to get the device name from the \'ohos.bluetooth.connection\'. ', 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
return "";
}
}
getCommandLineArguments()
{
let cmdLine : string = GetFromGlobalThis("CommandLineArguments")
if(cmdLine == undefined)
return ""
return cmdLine
}
}
!!REGISTER_BUILTIN_MODULE && REGISTER_BUILTIN_MODULE(MSG_RECEIVER.HOST_UI, new SystemSettings());
!!REGISTER_BUILTIN_MODULE && REGISTER_BUILTIN_MODULE(MSG_RECEIVER.HOST_UI, AppStorage);
\ No newline at end of file
import { REGISTER_BUILTIN_MODULE, MSG_RECEIVER } from '../workers/MessageProcessor';
import { GetFromGlobalThis } from '../common/GlobalThisUtil';
import { Context } from '@ohos.abilityAccessCtrl';
import util from '@ohos.util';
import dataPreferences from '@ohos.data.preferences';
class TuanjieAAID {
GetAAID() {
let context: Context = GetFromGlobalThis('AbilityContext');
let options: dataPreferences.Options = { name: 'tuanjieStore' };
let preferences = dataPreferences.getPreferencesSync(context, options);
let cachedKey = "tuanjie-cached-random-uuid";
if (preferences.hasSync(cachedKey)) {
return preferences.getSync(cachedKey, '');
}
let uuid = util.generateRandomUUID(true);
preferences.putSync(cachedKey, uuid);
preferences.flush((err) => {
if (err) {
console.error("Failed to flush. code =" + err);
return;
}
})
return uuid;
}
}
!!REGISTER_BUILTIN_MODULE && REGISTER_BUILTIN_MODULE(MSG_RECEIVER.HOST_UI, new TuanjieAAID());
import { batteryInfo } from '@kit.BasicServicesKit';
export class TuanjieBatteryInfo {
get batterySOC(): number {
return batteryInfo.batterySOC;
}
get chargingStatus(): number {
return batteryInfo.chargingStatus;
}
}
\ No newline at end of file
import { TuanjieLog } from '../common/TuanjieLog';
import { bundleManager } from '@kit.AbilityKit';
export class TuanjieBundleInfo {
versionCode: number = -1;
versionName: string = "";
vendor: string = "";
static async instance(): Promise<ESObject> {
const bundleInfo = new TuanjieBundleInfo();
try {
const data = await bundleManager.getBundleInfoForSelf(
bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT
);
bundleInfo.versionCode = data.versionCode;
bundleInfo.versionName = data.versionName;
bundleInfo.vendor = data.vendor;
return bundleInfo;
} catch (err) {
TuanjieLog.error("getBundleInfoForSelf failed. Cause: " + err.message);
return null;
}
}
}
\ No newline at end of file
import network from '@system.network';
import { REGISTER_BUILTIN_MODULE, MSG_RECEIVER } from '../workers/MessageProcessor';
enum NetworkReachability {
NotReachable,
ReachableViaCarrierDataNetwork,
ReachableViaLocalAreaNetwork
}
export class TuanjieInternet {
static internetState = NetworkReachability.NotReachable;
static Subscribe() {
network.subscribe({
success: (data) => {
console.log('network type change type:' + data.type);
if (data.metered) {
TuanjieInternet.internetState = NetworkReachability.ReachableViaCarrierDataNetwork;
}
else if (data.type == "WiFi") {
TuanjieInternet.internetState = NetworkReachability.ReachableViaLocalAreaNetwork;
}
else {
TuanjieInternet.internetState = NetworkReachability.NotReachable;
}
},
fail: (data: ESObject, code) => {
console.log('fail to subscribe network, code:' + code + ', data:' + data);
},
});
}
static GetInternetReachability() {
return TuanjieInternet.internetState;
}
}
!!REGISTER_BUILTIN_MODULE && REGISTER_BUILTIN_MODULE(MSG_RECEIVER.HOST_UI, TuanjieInternet);
import geoLocationManager from '@ohos.geoLocationManager';
import { TuanjieLog } from '../common/TuanjieLog';
import sensor from '@ohos.sensor'
import { POST_MESSAGE } from '../workers/WorkerProxy';
import { REGISTER_BUILTIN_MODULE, MSG_RECEIVER } from '../workers/MessageProcessor';
class TuanjieLocation {
requestLocationUpdates(timeInterval: number, distanceInterval: number, accuracy: number) {
let requestInfo:geoLocationManager.LocationRequest = {'priority': geoLocationManager.LocationRequestPriority.FIRST_FIX, 'scenario': geoLocationManager.LocationRequestScenario.UNSET,
'timeInterval': timeInterval, 'distanceInterval': distanceInterval, 'maxAccuracy': accuracy};
let locationChange = (location: geoLocationManager.Location):void => {
TuanjieLog.info('Update Location. Data: %{public}s',
JSON.stringify(location) ?? '');
POST_MESSAGE({
type: 'OnLocation',
location: location
});
};
try {
geoLocationManager.on('locationChange', requestInfo, locationChange);
} catch (err) {
TuanjieLog.error('Update Location Failed. Error: %{public}s',
JSON.stringify(err) ?? '');
}
}
removeUpdates() {
try {
geoLocationManager.off('locationChange');
} catch (err) {
TuanjieLog.error('Remove Updates Failed. Error: %{public}s',
JSON.stringify(err) ?? '');
}
}
async getDeclination(latitude: number, longitude: number, altitude: number, timestamp: number) {
let geoInfo = await sensor.getGeomagneticInfo({ latitude: latitude, longitude: longitude, altitude: altitude }, timestamp);
return geoInfo.deflectionAngle;
}
getLastKnownLocation() {
let loc = geoLocationManager.getLastLocation();
return [
loc.latitude,
loc.longitude,
loc.altitude,
loc.accuracy,
loc.speed,
loc.timeStamp,
loc.direction,
loc.timeSinceBoot,
];
}
}
!!REGISTER_BUILTIN_MODULE && REGISTER_BUILTIN_MODULE(MSG_RECEIVER.HOST_UI, new TuanjieLocation())
\ No newline at end of file
import tuanjie from 'libtuanjie.so';
export class Tuanjie {
/**
* Notifies engine TuanjiePlayerAbility created.
*/
public static nativeOnCreate(): void {
tuanjie.nativeOnCreate();
}
/**
* Notifies engine TuanjiePlayerAbility destroyed.
*/
public static nativeOnDestroy(): void {
tuanjie.nativeOnDestroy();
}
/**
* Pause engine loop.
*/
public static nativeOnPause(): void {
tuanjie.nativeOnPause();
}
/**
* Resume engine loop.
*/
public static nativeOnResume(): void {
tuanjie.nativeOnResume();
}
/**
* Notifies engine windowstage actived.
*/
public static nativeOnWindowStageActive(): void {
tuanjie.nativeOnWindowStageActive();
}
/**
* Notifies engine windowstage inacttived.
*/
public static nativeOnWindowStageInActive(): void {
tuanjie.nativeOnWindowStageInActive();
}
/**
* Init main worker.
*/
public static nativeSetWorker(): void {
tuanjie.nativeSetWorker();
}
/**
* Process message to ui thread.
*/
public static nativeProcessUIThreadMessage(): void {
tuanjie.nativeProcessUIThreadMessage();
}
/**
* Calls the method named methodName on every MonoBehaviour in this game object.
* @param methodName - Name of the method to call.
* @param value - Optional parameter for the method.
* @param options - Should an error be raised if the target object doesn't implement the method for the message?
*/
public static TuanjieSendMessage(methodName: string, value: ESObject, options: ESObject): void {
tuanjie.TuanjieSendMessage(methodName, value, options);
}
/**
* Notifies engine to update the input string.
*/
public static nativeSetInputString(): void {
tuanjie.nativeSetInputString();
}
/**
* Notifies engine softinput closed.
*/
public static nativeSoftInputClosed(): void {
tuanjie.nativeSoftInputClosed();
}
/**
* Set input selection.
* @param start - The starting position of the selected text.
* @param length - The end position of the selected text.
*/
public static nativeSetInputSelection(start: number, length: number): void {
tuanjie.nativeSetInputSelection(start, length);
}
/**
* Notifies engine display changed.
*/
public static nativeOnDisplayChanged(): void {
tuanjie.nativeOnDisplayChanged();
}
/**
* Request the user to grant access to a device resource or information that requires authorization.
* @param permissions - Permission array.
* @param result - Return status code.
* @param onGranted - Triggered when the user chooses Allow for permissions request.
* @param onDenied - Triggered when the user chooses Deny for permissions request.
*/
public static nativeGetPermissionRequestResult(permissions: string[], result: number, onGranted: ESObject, onDenied: ESObject): void {
tuanjie.nativeGetPermissionRequestResult(permissions, result, onGranted, onDenied);
}
/**
* Check if the user has granted access to a device resource or information that requires authorization.
* @param permission - Permission name.
* @param result - Return status code.
* @param onAuthorized - Triggered when the permission is authorized.
* @param onUnauthorized - Triggered when the permission is unauthorized.
*/
public static nativeGetPermissionAuthorizeResult(permission: string, result: number, onAuthorized: ESObject, onUnauthorized: ESObject): void {
tuanjie.nativeGetPermissionAuthorizeResult(permission, result, onAuthorized, onUnauthorized);
}
/**
* Notifies engine location changed.
* @param location - location data.
*/
public static nativeOnLocationChange(location: ESObject): void {
tuanjie.nativeOnLocationChange(location);
}
/**
* native call js method.
* @param resolved - Promise resolved.
* @param userData - userData.
* @param result - result.
*/
public static nativeInvokeJSResult(resolved: boolean, userData: ESObject, result: ESObject): void {
tuanjie.nativeInvokeJSResult(resolved, userData, result);
}
/**
* Whether to render outside the safe area.
*/
public static nativeGetIsRenderOutsizeSafeArea(): boolean {
return tuanjie.nativeGetIsRenderOutsizeSafeArea();
}
/**
* Get is avoid area changed.
*/
public static nativeGetIsAvoidAreaChange(safeArea: ESObject): void {
tuanjie.nativeGetIsAvoidAreaChange(safeArea);
}
/**
* DebuggerDialog closed or not.
*/
public static nativeDebuggerDialogClosed(): void {
tuanjie.nativeDebuggerDialogClosed();
}
}
import common from '@ohos.app.ability.common';
import { TuanjieLog } from '../common/TuanjieLog';
import uri from '@ohos.uri';
import Want from '@ohos.app.ability.Want';
import { REGISTER_BUILTIN_MODULE, MSG_RECEIVER } from '../workers/MessageProcessor';
export class TuanjieOpenURL {
OpenURL(urlStr: string){
let abilityContext: ESObject = globalThis.AbilityContext;
let context = abilityContext as common.UIAbilityContext;
const url = new uri.URI(urlStr);
let result = url.scheme == null? `https://${urlStr}` : urlStr;
let wantInfo: Want = {
'action': 'ohos.want.action.viewData',
'entities': ['entity.system.browsable'],
'uri':result
}
context.startAbility(wantInfo).then(() => {
}).catch((err: ESObject) => {
TuanjieLog.error("OpenURL failed, err: " + err);
})
}
}
!!REGISTER_BUILTIN_MODULE && REGISTER_BUILTIN_MODULE(MSG_RECEIVER.HOST_UI, new TuanjieOpenURL());
import { REGISTER_BUILTIN_MODULE, MSG_RECEIVER } from '../workers/MessageProcessor';
import { TuanjieLog } from '../common/TuanjieLog';
import { POST_MESSAGE } from '../workers/WorkerProxy';
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
import bundleManager from '@ohos.bundle.bundleManager';
// Matches enum in PermissionCallback.h
class PermissionResult {
static readonly Success: number = 0;
static readonly Failed: number = 1;
static readonly Error: number = 2;
}
export class TuanjiePermissions {
public static requestUserPermissions(permissionList: string, onGranted: number, onDenied: number): void {
let permissionsStr: Array<string> = permissionList.split(',');
TuanjieLog.info('requestUserPermissions enter.');
const atManager = abilityAccessCtrl.createAtManager();
let context: ESObject = globalThis.AbilityContext;
let permissions: Array<Permissions> = [];
permissionsStr.forEach(element => {
permissions.push(element as Permissions);
});
let permissionsSize: number = permissions.length;
let permissionResults: Array<number> = new Array(permissionsSize);
permissionResults.fill(PermissionResult.Error);
atManager.requestPermissionsFromUser(context, permissions, (err, data) => {
if (err) {
TuanjieLog.error('Failed to requestPermission. Cause: %{public}s',
JSON.stringify(err) ?? '');
} else {
TuanjieLog.info('Succeeded in requestPermission. Data: %{public}s',
JSON.stringify(data) ?? '');
for (let i = 0; i < permissionsSize; i++) {
if (data.authResults[i] == 0) {
permissionResults[i] = PermissionResult.Success;
} else {
permissionResults[i] = PermissionResult.Failed;
}
}
}
POST_MESSAGE({
type: 'GetPermissionRequestResult',
permissions: data.permissions,
results: permissionResults,
onGranted: onGranted,
onDenied: onDenied
});
})
}
public static checkAccessToken(permission: Permissions) : boolean{
let atManager = abilityAccessCtrl.createAtManager();
let grantStatus: abilityAccessCtrl.GrantStatus = -1;
// Obtain the access token ID of the application.
let tokenId: number = 0;
try {
let bundleInfo: bundleManager.BundleInfo =
bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
tokenId = appInfo.accessTokenId;
} catch (err) {
TuanjieLog.error('Failed to getBundleInfoForSelfSync. Cause: %{public}s',
JSON.stringify(err) ?? '');
}
// Check whether the user has granted the permission.
try {
grantStatus = atManager.checkAccessTokenSync(tokenId, permission);
} catch (err) {
TuanjieLog.error('Failed to checkAccessTokenSync. Cause: %{public}s',
JSON.stringify(err) ?? '');
}
return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
}
public static hasPermission(permissionsStr: string): boolean {
console.log(`hasPermission=${permissionsStr}`);
let permission = permissionsStr as Permissions;
let grantStatus = TuanjiePermissions.checkAccessToken(permission);
return grantStatus;
}
public static checkPermission(permissionsStr: string, onAuthorized: number, onUnauthorized: number): void {
let permission = permissionsStr as Permissions;
let checkResult = PermissionResult.Error;
try {
let grantStatus: boolean = TuanjiePermissions.checkAccessToken(permission);
if (grantStatus) {
checkResult = PermissionResult.Success;
} else {
checkResult = PermissionResult.Failed;
}
} catch (err) {
TuanjieLog.error('Failed to checkPermission. Cause: %{public}s',
JSON.stringify(err) ?? '');
} finally {
POST_MESSAGE({
type: 'GetPermissionAuthorizeResult',
permission: permission,
result: checkResult,
onAuthorized: onAuthorized,
onUnauthorized: onUnauthorized
});
}
}
}
!!REGISTER_BUILTIN_MODULE && REGISTER_BUILTIN_MODULE(MSG_RECEIVER.HOST_UI, TuanjiePermissions);
import vibrator from '@ohos.vibrator';
import { TuanjieLog } from '../common/TuanjieLog';
import { REGISTER_BUILTIN_MODULE, MSG_RECEIVER } from '../workers/MessageProcessor';
export class TuanjieVibrate {
vibrate(vibrateMs: number) {
try {
vibrator.startVibration({ type: 'time', duration: vibrateMs }, { id: 0, usage: 'alarm' }, (error) => {
if (error) {
console.error('Vibrate fail, error.code: ' + error.code + 'error.message: ${error.message}');
return;
}
console.log('Callback returned to indicate a successful vibration.');
});
} catch (err) {
console.error('errCode: ' + err.code + ' ,msg: ' + err.message);
}
TuanjieLog.info("Trigger Vibrate");
}
}
!!REGISTER_BUILTIN_MODULE && REGISTER_BUILTIN_MODULE(MSG_RECEIVER.HOST_UI, new TuanjieVibrate())
\ No newline at end of file
import { Tuanjie } from '../utils/TuanjieNative';
import { REGISTER_BUILTIN_MODULE, MSG_RECEIVER } from '../workers/MessageProcessor';
export enum EVideoStatus {
None = -1,
Play,
Pause,
Stop
}
export class VideoInfo {
public url: string = ""
public bgColor: number = 0
public controlMode: number = 0
public scalingMode: number = 0
public isPlaying: boolean = false
Init(url: string, bgColor: number, controlMode: number, scalingMode: number) {
this.url = url
this.bgColor = bgColor
this.controlMode = controlMode
this.scalingMode = scalingMode
this.isPlaying = true
}
}
export class VideoPlayerProxy {
static _instance:VideoPlayerProxy;
static getInstance() : VideoPlayerProxy {
if(!VideoPlayerProxy._instance)
{
VideoPlayerProxy._instance = new VideoPlayerProxy();
}
return VideoPlayerProxy._instance;
}
ShowVideoPlayer(path: string, backgroundColor: number, controlMode: number, scalingMode: number) {
let videoInfo = new VideoInfo()
videoInfo.Init(path, backgroundColor, controlMode, scalingMode)
AppStorage.setOrCreate('VideoInfo', videoInfo);
return true;
}
OnVideoStart() {
Tuanjie.nativeOnPause();
}
OnVideoStop() {
Tuanjie.nativeOnResume();
}
IsPlaying()
{
let info = AppStorage.get('VideoInfo') as VideoInfo;
return info && info.isPlaying;
}
OnResume()
{
AppStorage.setOrCreate('VideoStatus', EVideoStatus.Play);
}
OnPause()
{
AppStorage.setOrCreate('VideoStatus', EVideoStatus.Pause);
}
}
!!REGISTER_BUILTIN_MODULE && REGISTER_BUILTIN_MODULE(MSG_RECEIVER.HOST_UI, VideoPlayerProxy.getInstance());
import worker from '@ohos.worker';
import { POST_MESSAGE_TO_HOST } from '../workers/HostProxy';
const workerPort = worker.workerPort;
export class WebviewControl {
private messageStateCallback: Function | null = null;
private messageEventCallback: Function | null = null;
public constructor() {
globalThis.workerPort.addEventListener("message", async (e: ESObject) => {
let msg: ESObject = JSON.parse(JSON.stringify(e));
switch (msg.data.type) {
case "WebviewStateCallback":
if (this.messageStateCallback != null) {
this.messageStateCallback(
msg.data.index,
msg.data.state);
}
break;
case "WebviewEventCallback":
if (this.messageEventCallback != null) {
this.messageEventCallback(
msg.data.index,
msg.data.event,
msg.data.errorMsg);
}
break;
default:
break;
}
});
}
static _instance: WebviewControl;
static getInstance(): WebviewControl {
if (!WebviewControl._instance) {
WebviewControl._instance = new WebviewControl();
}
return WebviewControl._instance;
}
public InitializeCallback(stateCallback: () => void, eventCallback: () => void) {
this.messageStateCallback = stateCallback;
this.messageEventCallback = eventCallback;
}
public LoadHTMLString(index: number, contents: string, baseUrl: string): void {
POST_MESSAGE_TO_HOST({
type: "RUN_ON_UI_THREAD_JS",
funcName: "WebviewUtils.LoadHTMLString",
args: [index, contents, baseUrl]
});
}
public LoadData(index: number, contents: string, mimeType: string, encoding: string, baseUrl: string): void {
POST_MESSAGE_TO_HOST({
type: "RUN_ON_UI_THREAD_JS",
funcName: "WebviewUtils.LoadData",
args: [index, contents, mimeType, encoding, baseUrl]
});
}
public EvaluateJS(index: number, jsContents: string): void {
POST_MESSAGE_TO_HOST({
type: "RUN_ON_UI_THREAD_JS",
funcName: "WebviewUtils.EvaluateJS",
args: [index, jsContents]
});
}
public Reload(index: number): void {
POST_MESSAGE_TO_HOST({
type: "RUN_ON_UI_THREAD_JS",
funcName: "WebviewUtils.Reload",
args: [index]
});
}
public StopLoading(index: number): void {
POST_MESSAGE_TO_HOST({
type: "RUN_ON_UI_THREAD_JS",
funcName: "WebviewUtils.StopLoading",
args: [index]
});
}
public GoForward(index: number): void {
POST_MESSAGE_TO_HOST({
type: "RUN_ON_UI_THREAD_JS",
funcName: "WebviewUtils.GoForward",
args: [index]
});
}
public GoBack(index: number): void {
POST_MESSAGE_TO_HOST({
type: "RUN_ON_UI_THREAD_JS",
funcName: "WebviewUtils.GoBack",
args: [index]
});
}
public SyncWebviewInfos(webviewInfosJson: string) {
POST_MESSAGE_TO_HOST({
type: "RUN_ON_UI_THREAD_JS",
funcName: "WebviewUtils.SyncWebviewInfos",
args: [webviewInfosJson]
});
}
}
export function RegisterWebviewControl() {
let register: Record<string, Object> = {};
register["WebviewControl"] = WebviewControl;
return register;
}
import web_webview from '@ohos.web.webview'
import { WebviewInfo } from '../pages/components/TuanjieWebview';
import { REGISTER_BUILTIN_MODULE, MSG_RECEIVER } from '../workers/MessageProcessor';
export class WebviewUtils {
private static _webviewInfos: WebviewInfo[]; // Backing field for the static property
public static get webviewInfos(): WebviewInfo[] {
return AppStorage.get("webviewInfos") as WebviewInfo[]
}
public static set webviewInfos(value: WebviewInfo[]) {
AppStorage.setOrCreate("webviewInfos", value);
}
private static _controllers: web_webview.WebviewController[];
public static get controllers(): web_webview.WebviewController[] {
return AppStorage.get("controllers") as web_webview.WebviewController[]
}
public static set controllers(value: web_webview.WebviewController[]) {
AppStorage.setOrCreate("controllers", value);
}
LoadHTMLString(index: number, contents: string, baseUrl: string) {
WebviewUtils.controllers[index].loadData(contents, "text/html", "UTF-8", baseUrl);
}
LoadData(index: number, contents: string, mimeType: string, encoding: string, baseUrl: string) {
WebviewUtils.controllers[index].loadData(contents, mimeType, encoding, baseUrl);
}
EvaluateJS(index: number, jsContents: string) {
try {
WebviewUtils.controllers[index].runJavaScript(jsContents).then((result: ESObject) => {
if (result) {
console.info(`The return value is: ${result}`)
}
})
} catch (error) {
console.error('Failed to evaluate JavaScript. Cause: ' + JSON.stringify(error));
}
}
Reload(index: number) {
WebviewUtils.controllers[index].refresh();
}
StopLoading(index: number) {
WebviewUtils.controllers[index].stop();
}
GoForward(index: number) {
if (WebviewUtils.controllers[index].accessForward()) {
WebviewUtils.controllers[index].forward()
}
}
GoBack(index: number) {
if (WebviewUtils.controllers[index].accessBackward()) {
WebviewUtils.controllers[index].backward()
}
}
SyncWebviewInfos(webviewInfosJson: string) {
let webviews: WebviewInfo[] = JSON.parse(webviewInfosJson) as WebviewInfo[];
while (WebviewUtils.controllers.length < webviews.length) {
WebviewUtils.controllers.push(new web_webview.WebviewController());
}
WebviewUtils.webviewInfos = webviews;
}
}
!!REGISTER_BUILTIN_MODULE && REGISTER_BUILTIN_MODULE(MSG_RECEIVER.HOST_UI, new WebviewUtils())
\ No newline at end of file
import window from '@ohos.window';
import pasteboard from '@ohos.pasteboard';
import { GetFromGlobalThis } from '../common/GlobalThisUtil';
import { TuanjieLog } from '../common/TuanjieLog';
import { DebuggerDialogInfo } from './DebuggerDialogInfo';
import { APP_KEY_SAFEAREA_RECT } from '../common/Constants';
import { Tuanjie } from '../utils/TuanjieNative';
import { REGISTER_BUILTIN_MODULE, MSG_RECEIVER } from '../workers/MessageProcessor';
import { BusinessError } from '@ohos.base';
import { TuanjiePermissions } from '../utils/TuanjiePermissions';
// These MUST be synchronized with ScreenManager.h
enum ScreenOrientation {
kScreenOrientationUnknown,
kPortrait,
kPortraitUpsideDown,
kLandscapeLeft,
kLandscapeRight,
kAutoRotation,
kScreenOrientationCount
};
export class WindowUtils {
readonly MainWindowKey = "TuanjieMainWindow";
systemBarState: Array<'status' | 'navigation'> | null = null;
nativeToOpenHarmonyOrientationMap: Map<number, window.Orientation> = (() => {
let orientationMap = new Map<number, window.Orientation>();
orientationMap.set(ScreenOrientation.kScreenOrientationUnknown, window.Orientation.UNSPECIFIED);
orientationMap.set(ScreenOrientation.kPortrait, window.Orientation.PORTRAIT);
orientationMap.set(ScreenOrientation.kPortraitUpsideDown, window.Orientation.PORTRAIT_INVERTED);
orientationMap.set(ScreenOrientation.kLandscapeLeft, window.Orientation.LANDSCAPE);
orientationMap.set(ScreenOrientation.kLandscapeRight, window.Orientation.LANDSCAPE_INVERTED);
orientationMap.set(ScreenOrientation.kAutoRotation, window.Orientation.AUTO_ROTATION);
return orientationMap;
})();
static _instance: WindowUtils;
static getInstance(): WindowUtils {
if (!WindowUtils._instance) {
WindowUtils._instance = new WindowUtils();
}
return WindowUtils._instance;
}
getMainWindow(): window.Window {
return GetFromGlobalThis(this.MainWindowKey);
}
setWindowSizeChangeCallback() {
let windowClass: window.Window = this.getMainWindow();
try {
windowClass.on('windowSizeChange', (size) => {
this.setXComponentSizeWithSafeArea(size.width, size.height, Tuanjie.nativeGetIsRenderOutsizeSafeArea());
})
} catch (err) {
TuanjieLog.error('setWindowSizeChangeCallback failed, reason: ' + JSON.stringify(err))
}
}
setWindowAvoidAreaChangeCallBack() {
let windowClass: window.Window = this.getMainWindow();
try {
windowClass.on('avoidAreaChange', (data) => {
let safeArea = this.getSafeAreaWithNativeFormat(Tuanjie.nativeGetIsRenderOutsizeSafeArea());
Tuanjie.nativeGetIsAvoidAreaChange(safeArea);
this.setXComponentSizeWithSafeArea(0, 0, Tuanjie.nativeGetIsRenderOutsizeSafeArea());
})
} catch (err) {
TuanjieLog.error('setWindowAvoidAreaChangeCallBack failed, reason: ' + JSON.stringify(err))
}
}
setSystemBarState(systemBars: Array<string>) {
let requestedBars: ("status" | "navigation")[] = systemBars as ("status" | "navigation")[];
if (this.systemBarState != null &&
JSON.stringify(this.systemBarState) === JSON.stringify(requestedBars)) {
return;
}
let windowClass: window.Window = this.getMainWindow();
windowClass.setWindowSystemBarEnable(requestedBars).then(() => {
TuanjieLog.info('Succeeded in setting the system bar to be invisible.');
this.systemBarState = requestedBars;
}).catch((err: ESObject) => {
TuanjieLog.error('Failed to set the system bar to be invisible. Cause:' + JSON.stringify(err));
})
}
setOrientation(orientNum: number) {
if (!this.nativeToOpenHarmonyOrientationMap.has(orientNum)) {
return;
}
let orientation: window.Orientation | undefined = this.nativeToOpenHarmonyOrientationMap.get(orientNum);
let windowClass: window.Window = this.getMainWindow();
windowClass.setPreferredOrientation(orientation).then(() => {
TuanjieLog.info('Succeeded in setting the window orientation.');
}).catch((err: ESObject) => {
TuanjieLog.error('Failed to set the window orientation. Cause: ' + JSON.stringify(err));
})
}
getWindowAvoidArea(avoidAreaType: window.AvoidAreaType) {
let windowClass: window.Window = this.getMainWindow();
if (windowClass == null || windowClass == undefined) {
return null;
}
return windowClass.getWindowAvoidArea(avoidAreaType);
}
getSafeArea(width: number, height: number): window.Rect | null {
let cutoutAvoidArea: window.AvoidArea | null = this.getWindowAvoidArea(window.AvoidAreaType.TYPE_CUTOUT);
let systemAvoidArea: window.AvoidArea | null = this.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
if (cutoutAvoidArea == null) {
return null;
}
let cutoutSafeAreaLeft = cutoutAvoidArea.leftRect.left + cutoutAvoidArea.leftRect.width;
let cutoutSafeAreaTop = cutoutAvoidArea.topRect.top + cutoutAvoidArea.topRect.height;
let cutoutSafeAreaRight = cutoutAvoidArea.rightRect.left || width;
let cutoutSafeAreaBottom = cutoutAvoidArea.bottomRect.top || height;
if (systemAvoidArea == null) {
return {
left: cutoutSafeAreaLeft,
top: cutoutSafeAreaTop,
width: cutoutSafeAreaRight - cutoutSafeAreaLeft,
height: cutoutSafeAreaBottom - cutoutSafeAreaTop
};
}
let systemSafeAreaLeft = systemAvoidArea.leftRect.left + systemAvoidArea.leftRect.width;
let systemSafeAreaTop = systemAvoidArea.topRect.top + systemAvoidArea.topRect.height;
let systemSafeAreaRight = systemAvoidArea.rightRect.left || width;
let systemSafeAreaBottom = systemAvoidArea.bottomRect.top || height;
let safeAreaLeft = Math.max(cutoutSafeAreaLeft, systemSafeAreaLeft);
let safeAreaTop = Math.max(cutoutSafeAreaTop, systemSafeAreaTop);
let safeAreaRight = Math.min(cutoutSafeAreaRight, systemSafeAreaRight);
let safeAreaBottom = Math.min(cutoutSafeAreaBottom, systemSafeAreaBottom);
if (safeAreaRight <= safeAreaLeft || safeAreaBottom <= safeAreaTop) {
return null;
}
return {
left: safeAreaLeft,
top: safeAreaTop,
width: safeAreaRight - safeAreaLeft,
height: safeAreaBottom - safeAreaTop
};
}
calculateSafeArea(width: number, height: number): window.Rect | null {
let safeAreaRect: window.Rect | null = this.getSafeArea(width, height);
if (safeAreaRect == null) {
return null;
}
return {
left: safeAreaRect.left,
top: height - safeAreaRect.top - safeAreaRect.height,
width: safeAreaRect.width,
height: safeAreaRect.height
};
}
getSafeAreaWithNativeFormat(renderOutside: boolean) {
let windowRect = this.getMainWindow().getWindowProperties().windowRect;
let safeArea = this.calculateSafeArea(windowRect.width, windowRect.height);
if (safeArea == null) {
return [0, 0, 0, 0];
}
if (!renderOutside) {
return [0, 0, safeArea.width, safeArea.height];
}
return [safeArea.left, safeArea.top, safeArea.width, safeArea.height];
}
setXComponentSizeWithSafeArea(width: number, height: number, renderOutside: boolean) {
if (width == 0 || height == 0) {
let properties = this.getMainWindow().getWindowProperties();
width = properties.windowRect.width;
height = properties.windowRect.height;
}
let safeAreaWidth: number, safeAreaHeight: number, safeAreaXOffset: number, safeAreaYOffset: number;
if (renderOutside) {
safeAreaWidth = width;
safeAreaHeight = height;
safeAreaXOffset = 0;
safeAreaYOffset = 0;
} else {
let safeArea = this.getSafeArea(width, height);
if (safeArea == null) {
return;
}
safeAreaWidth = safeArea.width;
safeAreaHeight = safeArea.height;
safeAreaXOffset = safeArea.left;
safeAreaYOffset = safeArea.top;
}
AppStorage.setOrCreate<window.Rect>(APP_KEY_SAFEAREA_RECT, {
left: safeAreaXOffset,
top: safeAreaYOffset,
width: safeAreaWidth,
height: safeAreaHeight
});
}
fillCutoutArray(uint16Array: Uint16Array, rect: window.Rect, startIdx: number) {
uint16Array[startIdx++] = rect.left;
uint16Array[startIdx++] = rect.top;
uint16Array[startIdx++] = rect.width;
uint16Array[startIdx++] = rect.height;
return startIdx;
}
getCutouts(arrayBuffer: ArrayBuffer) {
let avoidArea: window.AvoidArea | null = this.getWindowAvoidArea(window.AvoidAreaType.TYPE_CUTOUT);
if (avoidArea == null) {
return null;
}
let uint16Array = new Uint16Array(arrayBuffer);
let startIndex: number = 0;
startIndex = this.fillCutoutArray(uint16Array, avoidArea.leftRect, startIndex);
startIndex = this.fillCutoutArray(uint16Array, avoidArea.topRect, startIndex);
startIndex = this.fillCutoutArray(uint16Array, avoidArea.rightRect, startIndex);
startIndex = this.fillCutoutArray(uint16Array, avoidArea.bottomRect, startIndex);
return arrayBuffer;
}
setScreenOn(value: boolean) {
let windowClass: window.Window = this.getMainWindow();
// only kNeverSleep & kSystemSetting are supported like other platforms
windowClass.setWindowKeepScreenOn(value);
}
moveTaskToBack() {
let windowClass: window.Window = this.getMainWindow();
windowClass.minimize((err: ESObject) => {
const errCode: number = err.code;
if (errCode) {
TuanjieLog.error(`Failed to minimize the window. Cause code: ${err.code}, message: ${err.message}`);
return;
}
TuanjieLog.info('Succeeded in minimizing the window.');
});
}
getPasteboard() {
let enableReadPasteboard : boolean = TuanjiePermissions.checkAccessToken('ohos.permission.READ_PASTEBOARD');
if(!enableReadPasteboard)
{
TuanjieLog.error('No permission \'ohos.permission.READ_PASTEBOARD\' to read the pasteboard.');
return "";
}
let sysPasteBoard = pasteboard.getSystemPasteboard();
let pasteData = sysPasteBoard.getDataSync();
if (pasteData) {
try
{
let number = pasteData.getRecordCount();
if (number == 0)
{
TuanjieLog.info('Failed to get text from the empty pasteboard.');
return "";
}
let record = pasteData.getPrimaryText();
TuanjieLog.info('Succeeded in reading the pasteboard.');
return record;
}
catch (err)
{
TuanjieLog.error('Failed to read the pasteboard. ', 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
return "";
}
}
return "";
}
setPasteboard(content: string) {
let sysPasteBoard = pasteboard.getSystemPasteboard();
let hasData = sysPasteBoard.hasDataSync();
if (hasData) {
let pasteData = sysPasteBoard.getDataSync();
let record = pasteboard.createRecord(pasteboard.MIMETYPE_TEXT_PLAIN, content);
let number = pasteData.getRecordCount();
if (number == 0) {
pasteData.addRecord(record)
} else {
pasteData.replaceRecord(0, record);
}
sysPasteBoard.setDataSync(pasteData);
} else {
let pasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, content);
sysPasteBoard.setDataSync(pasteData);
}
return true;
}
showSingleButtonDialog(dialogTitle: string, dialogMessage: string, dialogButtonText = "OK") {
DebuggerDialogInfo.setDebuggerDialogInfo(dialogTitle, dialogMessage, dialogButtonText, true);
}
}
!!REGISTER_BUILTIN_MODULE && REGISTER_BUILTIN_MODULE(MSG_RECEIVER.HOST_UI, WindowUtils.getInstance());
/**
* @desc Run on TuanjieMain worker thread, process message from UI thread and postMessage to UI thread
*/
import { Tuanjie } from '../utils/TuanjieNative';
import { TuanjieLog } from '../common/TuanjieLog';
import { registerJSScriptToCSharp } from '../gen/TuanjieJSScriptRegister';
import { TuanjieInternet } from '../utils/TuanjieInternet';
import { TuanjiePermissions } from '../utils/TuanjiePermissions';
import { PlayerPrefs } from '../common/PlayerPrefs'
import {
InitGlobalThisContext,
GetFromGlobalThis,
SetToGlobalThisContext,
SetToGlobalThis,
GetFromGlobalThisContext
} from '../common/GlobalThisUtil';
import { TuanjieDisplayInfo } from '../utils/DisplayInfoManager';
import { TuanjieBatteryInfo } from '../utils/TuanjieBatteryInfo';
import { TuanjieBundleInfo } from '../utils/TuanjieBundleInfo';
import { Message, REGISTER_HANDLER, MSG_RECEIVER,
PROCESS_TUANJIE_BUILTIN_MESSAGE, PROCESS_TUANJIE_HANDLER,
kCustomHandler,
PROCESS_TUANJIE_MESSAGE
} from "./MessageProcessor";
import "../gen/BuiltinWorkerMsgRegistration";
import geoLocationManager from '@ohos.geoLocationManager';
import worker from '@ohos.worker';
interface Location {
latitude: number,
longitude: number,
altitude: number,
accuracy: number,
speed: number,
timeStamp: number,
direction: number,
timeSinceBoot: number,
}
export class HostProxy {
async SetGlobalThisContext(msg: ESObject) {
InitGlobalThisContext(msg.data,PlayerPrefs,TuanjieInternet,TuanjiePermissions);
SetToGlobalThisContext("tuanjieJSScript", registerJSScriptToCSharp());
SetToGlobalThisContext("bundleInfo", await TuanjieBundleInfo.instance() as ESObject);
SetToGlobalThisContext("batteryInfo", new TuanjieBatteryInfo() as ESObject);
GetFromGlobalThisContext('TuanjieInternet').Subscribe();
}
Loop(msg: ESObject) {
console.log("message from main thread received!");
}
SetDisplayInfo(msg: ESObject) {
let defaultDisplay: TuanjieDisplayInfo = msg.data;
SetToGlobalThis('defaultDisplay', defaultDisplay);
Tuanjie.nativeOnDisplayChanged();
}
SoftInput_onTextChange (msg: ESObject) {
SetToGlobalThis("softInputMsg", msg.data);
TuanjieLog.debug("CustomDialogController worker thread SoftInput_onTextChange " + msg.data);
Tuanjie.nativeSetInputString();
}
SoftInput_onTextSelectionChange(msg: ESObject) {
Tuanjie.nativeSetInputSelection(msg.start, msg.length);
}
SoftInput_accept(msg: ESObject) {
TuanjieLog.debug("CustomDialogController worker thread SoftInput_accept " + msg.data);
Tuanjie.nativeSoftInputClosed();
}
SoftInput_cancel(msg: ESObject) {
// todo call tuanjie native api
}
GetPermissionRequestResult(msg: ESObject) {
Tuanjie.nativeGetPermissionRequestResult(msg.permissions, msg.results, msg.onGranted, msg.onDenied);
}
GetPermissionAuthorizeResult(msg: ESObject) {
Tuanjie.nativeGetPermissionAuthorizeResult(msg.permission, msg.result, msg.onAuthorized, msg.onUnauthorized);
}
OnLocation(msg: ESObject) {
let locationData: geoLocationManager.Location = msg.location;
let location: Location = {
latitude: 0,
longitude: 0,
altitude: 0,
accuracy: 0,
speed: 0,
timeStamp: 0,
direction: 0,
timeSinceBoot: 0
}; //default value
location.latitude = locationData.latitude;
location.longitude = locationData.longitude;
location.altitude = locationData.altitude;
location.accuracy = locationData.accuracy;
location.speed = locationData.speed;
location.timeStamp = locationData.timeStamp;
location.direction = locationData.direction;
location.timeSinceBoot = locationData.timeSinceBoot;
Tuanjie.nativeOnLocationChange(location);
}
InternetSubscribe(msg: ESObject) {
GetFromGlobalThisContext('TuanjieInternet').Subscribe();
}
PlayerPrefsLocalSave(msg: ESObject) {
GetFromGlobalThisContext('PlayerPrefs').LocalSave();
}
WebControllerAttached(msg: ESObject) {
}
}
let gHostProxy = new HostProxy();
export function GetHostProxy(): HostProxy {
return gHostProxy;
}
export function PROCESS_WORKER_MESSAGE(msg: Message): number {
let handlers: ESObject = GetHostProxy();
const func: ESObject = handlers[msg.type];
if (msg.type == "SetGlobalThisContext") { // async 函数特殊处理
handlers.SetGlobalThisContext(msg);
return 0;
}
if (!!func) {
func.apply(handlers,[msg]);
return 0;
} else if (msg.type == "RUN_ON_TUANJIEMAIN_THREAD_JS") {
PROCESS_TUANJIE_BUILTIN_MESSAGE(msg); // 自动注册的处理函数
} else if (msg.type == "RUN_ON_TUANJIEMAIN_THREAD_USER_EVENT") {
PROCESS_TUANJIE_MESSAGE(msg);
} else if (msg.type == kCustomHandler) {
PROCESS_TUANJIE_HANDLER(msg);
} else {
TuanjieLog.warn("Unknown message type=%{public}s", msg.type);
}
return -1;
}
export function POST_MESSAGE(msg: ESObject) {
POST_MESSAGE_TO_HOST(msg);
}
export function POST_MESSAGE_TO_HOST(msg: ESObject) {
if (!msg.type)
msg.type = "RUN_ON_UI_THREAD_USER_EVENT";
if (!!msg.callback) {
if (!msg.callbackFuncName)
msg.callbackFuncName = msg.funcName;
REGISTER_HANDLER(MSG_RECEIVER.WORKER_TUANJIE, msg.callbackFuncName, msg.callback);
msg.callback = undefined;
}
worker.workerPort.postMessage(msg);
}
import { POST_MESSAGE } from './WorkerProxy';
import { TuanjieLog } from '../common/TuanjieLog';
import { Tuanjie } from '../utils/TuanjieNative';
import { Init } from './MessageProcessor';
Init(POST_MESSAGE, TuanjieLog, Tuanjie);
// import { POST_MESSAGE } from './WorkerProxy';
// import { TuanjieLog } from '../common/TuanjieLog';
// import { Tuanjie } from '../utils/TuanjieNative';
function dummy(name: string) {
console.error(`${name} NOT INITIALIZED YET.`);
}
let POST_MESSAGE: ESObject = (obj: ESObject) => {
dummy("POST_MESSAGE");
}
let TuanjieLog: ESObject = {
info () {
dummy("TuanjieLog");
},
warn() {
dummy("TuanjieLog");
},
error() {
dummy("TuanjieLog");
},
};
let Tuanjie: ESObject = {
nativeInvokeJSResult() {
dummy("Tuanjie");
},
};
export function Init(pm: ESObject, tjl: ESObject, tj: ESObject) {
POST_MESSAGE = pm;
TuanjieLog = tjl;
Tuanjie = tj;
}
export interface Message {
type: string,
funcName: string, // moduleName.methodName
args: ESObject,
timeoutMs: number,
userData: ESObject | undefined,
modulePath: string | undefined,
callback: ESObject | undefined,
callbackFuncName: string | undefined,// callback 注册的名字(默认值等于 funcName); 如果 callback 为 undefined, 此字段无意义
};
export class MessageProcessor {
name: string;
m_builtinModules: Record<string, ESObject> = {};
m_customModules: Record<string, ESObject> | undefined = undefined;
m_customHandlers: Record<string, ESObject> | undefined = undefined;
constructor(name: string) {
this.name = name;
}
processMessage(msg: Message, builtinMsg: boolean = true) {
const tokens: ESObject = msg.funcName.split(".");
let mod: ESObject = undefined;
if (builtinMsg) {
mod = this.m_builtinModules[tokens[0]];
} else if (!!this.m_customModules) {
mod = this.m_customModules[tokens[0]];
}
if (!mod) {
TuanjieLog.error('%{public}s', "No module with name=" + tokens[0]);
Tuanjie.nativeInvokeJSResult(false, msg.userData, "No module with name=" + tokens[0]);
return;
}
const func: ESObject = mod[tokens[1]];
if (!func) {
TuanjieLog.error('%{public}s', "No funcname with name=" + msg.funcName);
Tuanjie.nativeInvokeJSResult(false, msg.userData, "No funcname with name=" + msg.funcName);
return;
}
let argsArr: Array<ESObject> = msg.args;
if (msg.timeoutMs >= 0) { // async
this.InvokeAsync(mod, func, argsArr, msg);
} else { // data.timeoutMs < 0, sync
this.InvokeSync(mod, func, argsArr, msg);
}
}
async processCustomMessage(msg: Message) {
if (!!msg.modulePath) {
const moduleName: ESObject = msg.funcName.split(".")[0]; // extract module name from funcName
await this.loadModule(moduleName, msg.modulePath);
}
this.processMessage(msg, false);
}
processHandler(msg: Message) {
if (!this.m_customHandlers) {
return;
}
try {
let func: ESObject = this.m_customHandlers[msg.funcName];
if (!!func) {
let args: Array<ESObject> = msg.args;
func(...args);
} else {
TuanjieLog.warn("No callback with name=%{public}s", msg.funcName);
}
} catch (err) {
TuanjieLog.error('Error occurred while calling callback=%{public}s, err=%{public}s', msg.funcName, err);
}
}
InvokeAsync(mod: ESObject, func: ESObject, argsArr: Array<ESObject>, msg: Message) {
let timeout: Promise<number> = new Promise((_, reject) => {
setTimeout(() => {
reject(new Error("Async call timeout"));
}, msg.timeoutMs);
});
let succ: ESObject = func.apply(mod, argsArr);
Promise.race([succ, timeout]).then((result: ESObject) => {
if (!!msg.callbackFuncName) { // remote, post result back
POST_MESSAGE({'type': kCustomHandler, 'funcName': msg.callbackFuncName, 'args': result});
} else { // local
Tuanjie.nativeInvokeJSResult(true, msg.userData, result);
}
}).catch((err: ESObject) => {
let errMsg = JSON.stringify(err) ?? "unknown error";
errMsg = "Error calling " + msg.funcName + "err=" + errMsg;
TuanjieLog.error('%{public}s', errMsg);
if (!msg.callbackFuncName)
Tuanjie.nativeInvokeJSResult(false, msg.userData, err);
});
}
InvokeSync(mod: ESObject, func: ESObject, argsArr: Array<ESObject>, msg: Message) {
try {
let result: ESObject = func.apply(mod, argsArr);
if (!!msg.callbackFuncName) { // remote, post result back
TuanjieLog.info('Call user extra module function : ' + msg.callbackFuncName + ' success');
POST_MESSAGE({ 'type': kCustomHandler, 'funcName': msg.callbackFuncName, 'args': result});
} else {
Tuanjie.nativeInvokeJSResult(true, msg.userData, result);
}
} catch (err) {
let errMsg = JSON.stringify(err) ?? "unknown error";
errMsg = "Error calling " + msg.funcName + "err=" + errMsg;
TuanjieLog.error('%{public}s', errMsg);
if (!msg.callbackFuncName)
Tuanjie.nativeInvokeJSResult(false, msg.userData, errMsg);
}
}
registerBuiltinModule(module: ESObject): boolean {
let name: string = module.name || module.constructor.name;
const curModule: ESObject = this.m_builtinModules[name];
if (!!curModule) {
TuanjieLog.error('Duplicated message=%{public}s handler', name);
return false;
}
this.m_builtinModules[name] = module;
return true;
}
unregisterBuiltinModule(module: ESObject) {
let name: string = module.name || module.constructor.name;
const curModule: ESObject = this.m_builtinModules[name];
if (!!curModule) {
this.m_builtinModules.deleteKey(name);
}
}
registerModule(handler: ESObject): boolean {
if (!this.m_customModules) {
this.m_customModules = {};
}
let name: string = handler.name || handler.constructor.name;
const curHandler: ESObject = this.m_customModules[name];
if (!!curHandler) {
TuanjieLog.error('Duplicated message=%{public}s handler', name);
return false;
}
this.m_customModules[name] = handler;
return true;
}
unregisterModule(name: string) {
if (!!this.m_customModules) {
const handler: ESObject = this.m_customModules[name];
if (!!handler) {
this.m_customModules.deleteKey(name);
}
}
}
async loadModule(moduleName: string, modulePath: string) {
if (!this.m_customModules) {
this.m_customModules = {};
}
const mod: ESObject = this.m_customModules[moduleName];
if (!!mod) {
TuanjieLog.info(`Message=${moduleName} handler/module already exists.`);
}
const self = this;
await import(modulePath).then((mod: ESObject) => {
TuanjieLog.info(`Load module ${moduleName} Successfully.`);
if (!!self.m_customModules)
self.m_customModules[moduleName] = mod[moduleName];
}).catch((reason: ESObject) => {
TuanjieLog.error(`Failed to load user extra module=${moduleName}`);
});
}
unloadModule(moduleName: string) {
this.unregisterModule(moduleName);
}
registerHandler(name: string, callback: ESObject) {
if (!this.m_customHandlers) {
this.m_customHandlers = {};
}
this.m_customHandlers[name] = callback;
}
unregisterHandler(name: string) {
if (!!this.m_customHandlers) {
const handler: ESObject = this.m_customHandlers[name];
if (!!handler) {
this.m_customHandlers.deleteKey(name);
}
}
}
}
export const kCustomHandler: string = "CustomHandler";
export enum MSG_RECEIVER {
HOST_UI = 0,
WORKER_TUANJIE,
};
const gMsgProcessors: Array<MessageProcessor> = [
new MessageProcessor("Host.UI"), // Host: Run on UI thread
new MessageProcessor("Worker.Tuanjie"), // Worker: Run on Tuanjie thread
];
export function REGISTER_BUILTIN_MODULE(receiver: MSG_RECEIVER, module: ESObject) {
if (receiver >= gMsgProcessors.length)
TuanjieLog.error(`REGISTER_BUILTIN_MODULE| Unknown message receiver=%{public}d`, receiver);
else
gMsgProcessors[receiver].registerBuiltinModule(module);
}
export function UNREGISTER_BUILTIN_MODULE(receiver: MSG_RECEIVER, module: ESObject) {
if (receiver >= gMsgProcessors.length)
TuanjieLog.error(`UNREGISTER_BUILTIN_MODULE| Unknown message receiver=%{public}d`, receiver);
else
gMsgProcessors[receiver].unregisterBuiltinModule(module);
}
export function REGISTER_MODULE(receiver: MSG_RECEIVER, module: ESObject) {
if (receiver >= gMsgProcessors.length)
TuanjieLog.error(`REGISTER_MODULE| Unknown message receiver=%{public}d`, receiver);
else
gMsgProcessors[receiver].registerModule(module);
}
export async function UNREGISTER_MODULE(receiver: MSG_RECEIVER, moduleName: string) {
if (receiver >= gMsgProcessors.length)
TuanjieLog.error(`UNREGISTER_MODULE| Unknown message receiver=%{public}d`, receiver);
else
gMsgProcessors[receiver].unregisterModule(moduleName);
}
export async function LOAD_MODULE(receiver: MSG_RECEIVER, moduleName: string, modulePath: string) {
if (receiver >= gMsgProcessors.length)
TuanjieLog.error(`LOAD_MODULE| Unknown message receiver=%{public}d`, receiver);
else
gMsgProcessors[receiver].loadModule(moduleName, modulePath);
}
export async function UNLOAD_MODULE(receiver: MSG_RECEIVER, moduleName: string) {
if (receiver >= gMsgProcessors.length)
TuanjieLog.error(`UNLOAD_MODULE| Unknown message receiver=%{public}d`, receiver);
else
gMsgProcessors[receiver].unloadModule(moduleName);
}
export function REGISTER_HANDLER(receiver: MSG_RECEIVER, name: string, handler: ESObject) {
if (receiver >= gMsgProcessors.length)
TuanjieLog.error(`REGISTER_HANDLER| Unknown message receiver=%{public}d`, receiver);
else
gMsgProcessors[receiver].registerHandler(name, handler);
}
export function UNREGISTER_HANDLER(receiver: MSG_RECEIVER, handlerName: string) {
if (receiver >= gMsgProcessors.length)
TuanjieLog.error(`UNREGISTER_HANDLER| Unknown message receiver=%{public}d`, receiver);
else
gMsgProcessors[receiver].unregisterHandler(handlerName);
}
// accessible api proxy
export function PROCESS_UI_BUILTIN_MESSAGE(msg: Message) {
gMsgProcessors[MSG_RECEIVER.HOST_UI].processMessage(msg, true);
}
export async function PROCESS_UI_MESSAGE(msg: Message) {
gMsgProcessors[MSG_RECEIVER.HOST_UI].processCustomMessage(msg);
}
export function PROCESS_UI_HANDLER(msg: Message) {
gMsgProcessors[MSG_RECEIVER.HOST_UI].processHandler(msg);
}
export function PROCESS_TUANJIE_BUILTIN_MESSAGE(msg: Message) {
gMsgProcessors[MSG_RECEIVER.WORKER_TUANJIE].processMessage(msg, true);
}
export function PROCESS_TUANJIE_MESSAGE(msg: Message) {
gMsgProcessors[MSG_RECEIVER.WORKER_TUANJIE].processCustomMessage(msg);
}
export function PROCESS_TUANJIE_HANDLER(msg: Message) {
gMsgProcessors[MSG_RECEIVER.WORKER_TUANJIE].processHandler(msg);
}
import { SetToGlobalThis } from '../common/GlobalThisUtil';
import { TuanjieLog } from '../common/TuanjieLog';
import { PROCESS_WORKER_MESSAGE } from "./HostProxy";
import { Tuanjie } from '../utils/TuanjieNative';
import worker from '@ohos.worker';
TuanjieLog.debug("tuanjie.nativeSetWorker");
Tuanjie.nativeSetWorker();
const workerPort = worker.workerPort
// This line makes workerPort available for native code
// not sure why, maybe compiler will optimize `const`
//globalThis.workerPort = workerPort;
SetToGlobalThis("workerPort", workerPort);
workerPort.onmessage = async (e) => {
PROCESS_WORKER_MESSAGE(e.data);
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment