* Copyright (c) Huawei Device Co., Ltd. 2024-2025. All rights reserved.
* 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 lazy { StoreManager } from '../../worker/StoreManager';
import lazy { HiLog } from '../../utils/HiLog';
import lazy { WindowAction } from './WindowAction';
import type BusinessError from '@ohos.base';
import window from '@ohos.window';
import type { UIContext } from '@ohos.arkui.UIContext';
import lazy { ContextAction } from '../../redux/actions/ContextAction';
import type { Size } from '../../utils/types';
import lazy { DeviceInfo } from '../../component/deviceinfo/DeviceInfo';
import lazy { XComponentService } from '../../component/xcomponent/XComponentService';
import lazy { AdaptiveLayoutService } from '../UIAdaptive/AdaptiveLayoutService';
import settings from '@ohos.settings';
import lazy { GlobalContext } from '../../utils/GlobalContext';
import lazy { PersistType, PreferencesService } from '../preferences/PreferencesService';
import lazy { PublicTag } from '../preferences/PropTag';
import lazy { ContextManager } from '../context/ContextManager';
import lazy { WindowDirection } from '../../utils/WindowDirection';
import dataShare from '@ohos.data.dataShare';
import lazy { DisplayService } from '../UIAdaptive/DisplayService';
import lazy { common, ConfigurationConstant } from '@kit.AbilityKit';
import lazy { display } from '@kit.ArkUI';
import lazy { PickerUtils } from '../../utils/PickerUtils';
import lazy { simpleStringify } from '../../utils/SimpleStringify';
import lazy { ModeType } from '../../mode/ModeType';
import lazy { EventBus } from '../../worker/eventbus/EventBus';
import lazy { EventBusManager } from '../../worker/eventbus/EventBusManager';
import lazy { BaseComponent } from '../../worker/BaseComponent';
import lazy { execDispatch, getStates } from '../../redux';
import lazy { camera } from '@kit.CameraKit';
import lazy { CameraActionType } from '../../redux/actions/CameraActionType';
import lazy { ContextActionType } from '../../redux/actions/ContextActionType';
import lazy { isLogStyleSupport } from '../../function/enumbase/LogStyleMode';
import lazy { PhotoBrowserStatusData } from '../../camera/DataType';
import lazy { ThumbnailActionType } from '../../redux/actions/ThumbnailActionType';
import lazy { DataUriType, SettingsDataShareUtils } from '../../utils/SettingsDataShareUtils';
import lazy { FeatureManager } from '../../function/core/FeatureManager';
import lazy { FunctionId } from '../../function/core/functionproperty/FunctionId';
import lazy { AspectRatioOperation } from '../../function/aspectratio/AspectRatioOperation';
import lazy { CameraAction } from '../../camera/uithread/CameraAction';
import lazy { OutputSwitcher } from '../../function/outputswitcher/OutputSwitcher';
import lazy { OutputType } from '../../function/outputswitcher/OutputType';
import lazy { SettingsValueUtil } from '../../utils/SettingsValueUtil';
const STATUS_BAR_COLOR: string = '#00000000';
const STATUS_BAR_CONTENT_COLOR: string = '#FFFFFFFF';
const NAVIGATION_BAR_COLOR: string = '#00000000';
const NAVIGATION_BAR_CONTENT_COLOR: string = '#FFFFFFFF';
const TAG: string = 'WindowService';
const AI_BAR_DISPLAY_DELAY: number = 2000;
const FOUR_DIRECTION: number = 4;
export const DIFFER_TOLERANCE = 4;
const WAIT_TIME: number = 100;
const PC_DIFFER_TOLERANCE = 10;
const RATIO_ACCURACY: number = 2;
const WIN_DECOR_HEIGHT: number = 70;
const PCPICKER_WAIT_TIME = 500;
const WINDOW_PCMODE_SWITCH_STATUS: string = 'window_pcmode_switch_status';
导航栏类型枚举 0-三键 1-AI bar
*/
export enum NavigationStyle {
THREE_KEY = '0',
AI_BAR = '1',
}
* state true-显示 false-隐藏
* animation: true 是否需要动画 false 不需要动画
* keepConstantDisplay: true 常显 false 不常显
*/
class AIBarStyle {
public state: boolean;
public animation: boolean;
public keepConstantDisplay: boolean;
}
export const pxChange: (size: Size) => Size = (size: Size) => {
return { width: Math.floor(px2vp(size.width)), height: Math.floor(px2vp(size.height)) };
};
export class WindowService {
private mBase: BaseComponent = new BaseComponent();
private mEventBus: EventBus = EventBusManager.getInstance().getEventBus();
private static sInstanceWindowService: WindowService;
private mWindow: window.Window;
private rect: window.Rect;
private initializedFloating: boolean = false;
private cutoutAvoidArea: window.AvoidArea;
private isLocked: boolean = false;
private windowStatus: window.WindowStatusType | undefined = undefined;
private windowVisibilityStatus: boolean = false;
private accelerometerStatus: string = '0';
private timerId: number = Number.MIN_VALUE;
private settingDataHelper: dataShare.DataShareHelper = undefined;
private collapsTimer: number = Number.NaN;
private oldRatio: number = 0;
private isWindowRotationChangeLocked: boolean = false;
private isSetWaterMarkFlag: boolean = false;
private dragTimer: number = -1;
private navigationStyle: NavigationStyle = this.initNavigationStyle();
private aiBarStyle: AIBarStyle = new AIBarStyle();
public static windowMap: Map<number, boolean> = new Map();
public static getInstance(): WindowService {
if (!WindowService.sInstanceWindowService) {
WindowService.sInstanceWindowService = new WindowService();
}
return WindowService.sInstanceWindowService;
}
private constructor() {
this.mEventBus.on(CameraActionType.STARTED, () => this.setWaterMarkFlag(), this.mBase.hashCode());
this.mEventBus.on(ContextActionType.ABILITY_ON_BACKGROUND, () => this.onBackground(), this.mBase.hashCode());
this.mEventBus.on(ThumbnailActionType.PHOTOBROWSER_STATUS,
(data: PhotoBrowserStatusData) => this.onPhotoBrowserStatusChange(data), this.mBase.hashCode());
}
public init(win): void {
HiLog.i(TAG, 'init WindowService.');
this.mWindow = win;
execDispatch(WindowAction.onClassReady());
this.setWaterMarkFlag();
try {
if (DeviceInfo.isPc() || DeviceInfo.isTablet()) {
this.windowStatus = this.mWindow.getWindowStatus();
execDispatch(WindowAction.updateWindowStatus(this.windowStatus));
}
this.mWindow.on('windowStatusChange', (status: window.WindowStatusType) => {
HiLog.i(TAG, `windowStatusChange, status: ${status}.`);
if (status === window.WindowStatusType.MINIMIZE) {
return;
}
let windowPreStatus: window.WindowStatusType = this.windowStatus;
this.windowStatus = status;
execDispatch(WindowAction.updateWindowStatus(this.windowStatus, windowPreStatus));
});
this.mWindow.on('windowVisibilityChange', (status: boolean) => {
HiLog.i(TAG, `windowVisibilityChange, status: ${status}.`);
this.windowVisibilityStatus = status;
execDispatch(WindowAction.updateWindowVisibilityStatus(this.windowVisibilityStatus));
});
this.mWindow.on('windowEvent', (event: window.WindowEventType) => {
AppStorage.setOrCreate('WindowEventType', event);
});
this.navigationStyle = this.initNavigationStyle();
HiLog.d(TAG, 'registerKeyObserver floatingNavigation E');
settings.registerKeyObserver(ContextManager.getInstance().getAbilityContext(), 'floatingNavigation',
settings.domainName.USER_PROPERTY, () => {
this.dealWithNavigationStyleChange();
});
HiLog.d(TAG, 'registerKeyObserver floatingNavigation X');
if (DeviceInfo.isTablet() && GlobalContext.get().getIsPicker()) {
this.registerPcModeStatus();
this.updateSupportedWindowModes(PickerUtils.getIsInPcMode());
}
} catch (error) {
HiLog.i(TAG, `windowStatusChange on error: ${error}.`);
}
}
public setWindowBackGround(isBackGround: boolean): void {
try {
const win: number = this.mWindow.getWindowProperties().id;
HiLog.i(TAG, `setWindowBackGround: ${win}, ${isBackGround}`);
WindowService.windowMap.set(win, isBackGround);
} catch (err) {
HiLog.e(TAG, `setWindowBackGround fail. ${err?.code}`);
}
}
private isFloatingSwitch(curStatus: window.WindowStatusType, lastStatus: window.WindowStatusType): boolean {
if (curStatus === window.WindowStatusType.FLOATING && lastStatus === window.WindowStatusType.FULL_SCREEN ||
curStatus === window.WindowStatusType.FULL_SCREEN && lastStatus === window.WindowStatusType.FLOATING) {
return true;
}
return false;
}
private isSplitSwitch(curStatus: window.WindowStatusType, lastStatus: window.WindowStatusType): boolean {
if (curStatus === window.WindowStatusType.SPLIT_SCREEN && lastStatus === window.WindowStatusType.FULL_SCREEN ||
curStatus === window.WindowStatusType.FULL_SCREEN && lastStatus === window.WindowStatusType.SPLIT_SCREEN) {
return true;
}
return false;
}
public getMainWindow(): window.Window {
return this.mWindow;
}
private registerPcModeStatus(): void {
HiLog.d(TAG, 'registerPcModeStatus');
try {
settings.registerKeyObserver(ContextManager.getInstance().getAbilityContext(), WINDOW_PCMODE_SWITCH_STATUS,
settings.domainName.USER_PROPERTY, () => {
settings.getValue(ContextManager.getInstance().getAbilityContext(), WINDOW_PCMODE_SWITCH_STATUS,
settings.domainName.USER_PROPERTY).then((data) => {
HiLog.d(TAG, `registerPcModeStatus settings value changed: ${JSON.stringify(data)}`);
this.updateSupportedWindowModes(data === 'true');
});
});
} catch (err) {
HiLog.e(TAG, `registerPcModeStatus err. ${err?.code}`);
}
}
private updateSupportedWindowModes(isInPcMode: boolean): void {
HiLog.d(TAG, `updateSupportedWindowModes,isInPcMode: ${isInPcMode}`);
try {
let windowStage: window.WindowStage = GlobalContext.get().getWindowStage();
if (isInPcMode) {
windowStage.setSupportedWindowModes([0]);
} else {
windowStage.setSupportedWindowModes([0, 1]);
}
} catch (err) {
HiLog.e(TAG, `updateSupportedWindowModes err. ${err?.code}`);
}
}
public unRegisterPcModeStatus(): void {
HiLog.d(TAG, 'unRegisterPcModeStatus');
try {
settings.unregisterKeyObserver(ContextManager.getInstance().getAbilityContext(), WINDOW_PCMODE_SWITCH_STATUS,
settings.domainName.USER_PROPERTY);
} catch (err) {
HiLog.e(TAG, `unRegisterPcModeStatus err. ${err?.code}`);
}
}
unRegisterKeyObserverFloatingNavigation(): void {
HiLog.d(TAG, 'unRegisterKeyObserverFloatingNavigation');
try {
settings.unregisterKeyObserver(ContextManager.getInstance().getAbilityContext(), 'floatingNavigation',
settings.domainName.USER_PROPERTY);
} catch (err) {
HiLog.e(TAG, `unRegisterKeyObserverFloatingNavigation err. ${err?.code}`);
}
}
public reSetWin(win): void {
HiLog.i(TAG, 'reSetWind .');
this.mWindow = win;
try {
this.windowStatus = 1
}catch (err) {
HiLog.e(TAG, `reSetWin err. ${err?.code}`);
}
}
private onBackground(): void {
this.isSetWaterMarkFlag = false;
this.windowStatus = window.WindowStatusType.FULL_SCREEN;
execDispatch(WindowAction.updateWindowStatus(this.windowStatus));
}
private isWindowFullScreen(): boolean {
let windowStatus: window.WindowStatusType = this.getWindowStatus();
return windowStatus === window.WindowStatusType.FULL_SCREEN || windowStatus === window.WindowStatusType.MINIMIZE;
}
private isFullScreenExpandMode(): boolean {
let isWindowFull = this.isWindowFullScreen();
return isWindowFull;
}
public setLockWindowRotation(value: boolean): void {
HiLog.i(TAG, 'setLockWindowRotation:' + value);
if (!this.isFullScreenExpandMode() && !DeviceInfo.isTablet()) {
HiLog.i(TAG, 'not lockScreenRot for neither TAH nor tablet');
return;
}
let systemWindowLockSetting: string = this.getSettingsValueAccRotationStatus();
if ('0' === systemWindowLockSetting) {
HiLog.i(TAG, 'not lockScreenRot for already sysLocked');
return;
}
if (value) {
this.lockWindowRotation();
}
this.isWindowRotationChangeLocked = value;
if (!value) {
this.unlockWindowRotation();
}
}
public getWindowDisplayName(): string {
try {
HiLog.d(TAG, `getWindowDisplayName displayId:${AppStorage.get('windowDisplayId')}`);
return display.getDisplayByIdSync(AppStorage.get('windowDisplayId')).name;
} catch (err) {
HiLog.e(TAG, `getWindowDisplayName err. ${err}`);
return 'UNKNOWN';
}
}
public setForceUnlockWindowRotation(isLockUiToWindow: boolean): void {
HiLog.i(TAG, 'setUnlockWindowRotation:');
let systemWindowLockSetting: string = this.getSettingsValueAccRotationStatus();
if ('0' === systemWindowLockSetting) {
HiLog.i(TAG, 'not unlockScreenRot for already sysLocked');
return;
}
if (this.isWindowRotationChangeLocked) {
this.isWindowRotationChangeLocked = false;
this.unlockWindowRotation(isLockUiToWindow);
}
}
private unlockWindowRotation(isLockUiToWindow: boolean = true): void {
HiLog.i(TAG, 'unlockWindowRotation');
let orientation = window.Orientation.FOLLOW_DESKTOP;
this.setWinOrientation(orientation);
if (!DeviceInfo.isTablet() && isLockUiToWindow) {
execDispatch(WindowAction.onRotationLocked(false));
}
}
private lockWindowRotation(): void {
let disRotation: number = DisplayService.getInstance().getDisplay().rotation;
let orientation: window.Orientation = window.Orientation.FOLLOW_DESKTOP;
HiLog.i(TAG, 'lock window rotation:' + disRotation);
switch (disRotation) {
case 0:
orientation = window.Orientation.PORTRAIT;
break;
case 1:
orientation = window.Orientation.LANDSCAPE_INVERTED;
break;
case 2:
orientation = window.Orientation.PORTRAIT_INVERTED;
break;
case 3:
orientation = window.Orientation.LANDSCAPE;
break;
default:
break;
}
this.setWinOrientation(orientation);
if (window.Orientation.FOLLOW_DESKTOP !== orientation && !DeviceInfo.isTablet()) {
execDispatch(WindowAction.onRotationLocked(true));
}
}
public getSettingsValueAccRotationStatus(): string {
return SettingsValueUtil.getValueSync(settings.general.ACCELEROMETER_ROTATION_STATUS, '0');
}
public registerAccelerometer(): void {
this.accelerometerStatus = this.getSettingsValueAccRotationStatus();
execDispatch(WindowAction.onRotationStatusChange(this.accelerometerStatus === '0'));
SettingsDataShareUtils.createDataHelper(SettingsDataShareUtils.getSettingsUri(DataUriType.SETTING_GLOBAL_URI,
settings.general.ACCELEROMETER_ROTATION_STATUS, true))?.then((dataHelper: dataShare.DataShareHelper) => {
this.settingDataHelper = dataHelper;
if (!this.settingDataHelper) {
HiLog.e(TAG, 'createDataHelper is undefined');
return;
}
SettingsDataShareUtils.registerDataChange(this.settingDataHelper,
SettingsDataShareUtils.getSettingsUri(DataUriType.SETTING_GLOBAL_URI,
settings.general.ACCELEROMETER_ROTATION_STATUS, true), () => {
let currentAccStatus = this.getSettingsValueAccRotationStatus();
if (this.accelerometerStatus === currentAccStatus) {
return;
}
this.accelerometerStatus = currentAccStatus;
execDispatch(WindowAction.onRotationStatusChange(this.accelerometerStatus === '0'));
HiLog.i(TAG, `ACCELEROMETER_ROTATION_STATUS : ${this.accelerometerStatus}.`);
});
});
}
public unRegisterAccelerometer(): void {
if (!this.settingDataHelper) {
HiLog.e(TAG, 'unRegisterAccelerometer DataHelper is undefined');
return;
}
SettingsDataShareUtils.unRegisterDataChange(this.settingDataHelper,
SettingsDataShareUtils.getSettingsUri(DataUriType.SETTING_GLOBAL_URI,
settings.general.ACCELEROMETER_ROTATION_STATUS, true));
}
public getUiContext(): UIContext | undefined {
try {
return this.mWindow?.getUIContext();
} catch (err) {
HiLog.e(TAG, `Window getUiContext err: ${err}.`);
}
}
public setAspectRatio(ratio: number): void {
try {
this.mWindow?.setAspectRatio(ratio);
} catch (err) {
HiLog.e(TAG, `Window setAspectRatio err: ${err}.`);
}
}
private resizePcPickerWindow(ratio: number): void {
if (this.dragTimer !== -1) {
clearTimeout(this.dragTimer);
}
this.dragTimer = setTimeout(() => {
let tempProperties = this.mWindow?.getWindowProperties();
let tempWinTitleHeight = this.mWindow?.getWindowDecorHeight();
this.mWindow?.resize((tempProperties?.windowRect?.height - tempWinTitleHeight * 2) * ratio,
tempProperties?.windowRect?.height);
}, PCPICKER_WAIT_TIME);
}
public onWindowSizeChange(): void {
if (!this.mWindow) {
HiLog.e(TAG, 'window undefined, onWindowSizeChange error.');
return;
}
try {
this.mWindow.getUIContext().runScopedTask(() => {
const originalSize = this.mWindow.getWindowProperties().windowRect;
const callback = this.createWindowSizeCallback();
let size = callback(originalSize);
HiLog.i(TAG, `onWindowSizeChange windowRect: ${simpleStringify(this.mWindow.getWindowProperties().windowRect)
}, size: ${simpleStringify(size)}.`);
execDispatch(WindowAction.onSizeChange(size));
this.mWindow.on('windowSizeChange', this.windowSizeChangeCallback(callback).bind(this));
});
} catch (err) {
HiLog.e(TAG, `getUIContext err: ${err}.`);
}
}
private createWindowSizeCallback(): (size: Size) => Size {
return (size: Size): Size => {
let newSize: Size = size;
if (DeviceInfo.isPc()) {
const rect = this.mWindow.getWindowProperties().drawableRect;
newSize = {
width: size.width - rect.left,
height: size.height - rect.top,
};
HiLog.i(TAG, `window size: ${simpleStringify(size)}, px drawableRect: ${simpleStringify(rect)}, new size: ${
simpleStringify(newSize)}.`);
}
return pxChange(newSize);
};
}
public refreshWindowSize(densityPixels: number): void {
if (!this.mWindow) {
return;
}
try {
const size = {
width: this.mWindow?.getWindowProperties()?.windowRect.width / densityPixels,
height: this.mWindow?.getWindowProperties()?.windowRect.height / densityPixels
};
execDispatch(WindowAction.onSizeChange(size));
} catch (err) {
HiLog.e(TAG, `refreshWindowSize err. ${err}`);
}
}
private windowSizeChangeCallback(callback: (size: window.Size) => window.Size): BusinessError.Callback<window.Size> {
return async (size: Size) => {
size = callback(size);
HiLog.i(TAG, `windowSizeChange, width: ${size.width}, height: ${size.height}.`);
if (!AppStorage.get('isLemCollaps') || AppStorage.get('isPSDCollaps')) {
execDispatch(WindowAction.onSizeChange(size));
}
if (PickerUtils.getIsPicker()) {
PickerUtils.updatePickerWindowType(size);
}
if (!this.initializedFloating) {
return;
}
const isShowDefault = getStates().get<boolean>('collapsReducer', 'isShowDefault');
const isShowLandscape = getStates().get<boolean>('collapsReducer', 'isShowLandscape');
const isShowSettingView = getStates().get<boolean>('settingViewReducer', 'isShowSettingView');
if (isShowDefault || isShowLandscape || isShowSettingView) {
return;
}
if (!Number.isNaN(this.collapsTimer)) {
clearTimeout(this.collapsTimer);
}
this.collapsTimer = setTimeout(() => {
HiLog.i(TAG, 'changeShowLandscape to open.');
this.collapsTimer = Number.NaN;
}, WAIT_TIME);
};
}
public setWindowKeepScreenOn(isKeepScreenOn: boolean): void {
HiLog.i(TAG, `setting the screen to be always on. Data: ${isKeepScreenOn}.`);
this.mWindow?.setWindowKeepScreenOn(isKeepScreenOn).then((v) => {
HiLog.i(TAG, `Succeeded in setting the screen to be always on. Data: ${JSON.stringify(v)}.`);
StoreManager.getInstance().postMessage(ContextAction.updateScreenOnState(isKeepScreenOn));
}).catch((err: BusinessError.BusinessError) => {
HiLog.e(TAG, `Failed to set the screen to be always on. Cause: ${JSON.stringify(err)}.`);
});
}
public getWindowKeepScreenOn(): boolean {
try {
return this.mWindow?.getWindowProperties().isKeepScreenOn;
} catch (err) {
HiLog.e(TAG, `getWindowProperties fail. ${err}`);
return false;
}
}
public async setFullScreen(): Promise<void> {
if (!this.mWindow) {
HiLog.e(TAG, 'window undefined, setFullScreen error.');
return;
}
try {
if (PickerUtils.getIsInPcMode()) {
await this.mWindow.maximize(window.MaximizePresentation.ENTER_IMMERSIVE);
this.mWindow.setWindowTitleButtonVisible(false, false, true);
HiLog.e(TAG, `IsInPcMode. true`);
} else {
await this.mWindow.setWindowLayoutFullScreen(true);
HiLog.e(TAG, `IsInPcMode. false`);
}
HiLog.i(TAG, 'Camera setFullScreen finished.');
const preferences = PreferencesService.getInstance();
this.mWindow?.setSpecificSystemBarEnabled('status', false, false).then(() => {
HiLog.e(TAG, 'setSpecificSystemBarEnabled status false');
}).catch((err) => {
HiLog.e(TAG, `setSpecificSystemBarEnabled status err. ${err?.code}`);
});
this.mWindow?.setSpecificSystemBarEnabled('navigation', true, false).then(() => {
HiLog.e(TAG, 'setSpecificSystemBarEnabled navigation false');
}).catch((err) => {
HiLog.e(TAG, `setSpecificSystemBarEnabled status err. ${err?.code}`);
});
HiLog.i(TAG, 'Camera setSystemBarEnable finished.');
await this.mWindow.setWindowSystemBarProperties({
statusBarColor: STATUS_BAR_COLOR,
statusBarContentColor: STATUS_BAR_CONTENT_COLOR,
navigationBarColor:NAVIGATION_BAR_COLOR,
navigationBarContentColor: NAVIGATION_BAR_CONTENT_COLOR
});
HiLog.i(TAG, 'Camera setSystemBarProperties.');
} catch (err) {
HiLog.i(TAG, 'Camera setFullScreen err: ' + err);
}
}
public getWindowRect(): window.Rect {
if (this.rect) {
return this.rect;
} else {
try {
return this.mWindow?.getWindowProperties()?.windowRect;
} catch (err) {
HiLog.e(TAG, 'getWindowRect err: ' + err);
}
}
}
public setWindowRect(rect: window.Rect): void {
this.rect = rect;
}
public setWinOrientation(orientation: window.Orientation): void {
if (this.isWindowRotationChangeLocked) {
HiLog.i(TAG, 'rot locked in immersive');
return;
}
const isShowPhotoBrowser: boolean | undefined = AppStorage.get('showPhotoBrowserAction');
if (isShowPhotoBrowser) {
HiLog.w(TAG, 'setPreferredOrientation return PhotoBrowser isShow');
return;
}
HiLog.i(TAG, `setPreferredOrientation: ${orientation}`);
this.clearTimer();
this.timerId = setTimeout((): void => {
this.timerId = Number.MIN_VALUE;
let setSuccess = true;
try {
this.mWindow?.setPreferredOrientation(orientation).then(() => {
HiLog.i(TAG, 'Camera setPreferredOrientation finished.');
}).catch((err) => {
HiLog.e(TAG, `Camera setPreferredOrientation err: ${err?.code}`);
setSuccess = false;
});
} catch (err) {
setSuccess = false;
HiLog.e(TAG, `Camera setPreferredOrientation err1: ${err?.code}`);
}
if (setSuccess) {
let windowLockDir: WindowDirection = this.orientationToWindowDirection(orientation);
HiLog.i(TAG, 'windowLockDirection:' + windowLockDir);
execDispatch(WindowAction.updateWindowLockDir(windowLockDir));
}
}, (orientation === window.Orientation.FOLLOW_DESKTOP && !AppStorage.get('isLemCollaps')) ? 300 : 0);
}
public getWinOrientation(): window.Orientation {
try {
return this.mWindow?.getPreferredOrientation();
} catch (err) {
HiLog.e(TAG, `getWinOrientation err: ${err}.`);
}
}
public isVertical(): boolean {
return getStates().get<number>('windowReducer', 'windowWidth') <
getStates().get<number>('windowReducer', 'windowHeight');
}
* 设置主窗口是否可以点击
* @param isTouchable
*/
public setWindowTouchable(isTouchable: boolean): void {
this.mWindow?.setWindowTouchable(isTouchable, (err) => {
if (err?.code) {
HiLog.e(TAG, 'Failed to set the window to be touchable. Cause:' + err?.code);
return;
}
HiLog.i(TAG, 'Succeeded in setting the window to be touchable.');
});
}
public initFloatingService(): void {
this.initializedFloating = true;
}
public initAvoidArea(): void {
try {
this.cutoutAvoidArea = this.mWindow?.getWindowAvoidArea(window.AvoidAreaType.TYPE_CUTOUT);
HiLog.i(TAG, `windowAvoidArea Area: ${JSON.stringify(this.cutoutAvoidArea)}.`);
this.changeTopAvoidArea();
this.mWindow?.on('avoidAreaChange', (data: {
type: window.AvoidAreaType,
area: window.AvoidArea
}) => {
if (data.type === window.AvoidAreaType.TYPE_CUTOUT) {
this.cutoutAvoidArea = data.area;
} else {
return;
}
HiLog.i(TAG, `avoidAreaChange, type: ${data.type}, rect: ${JSON.stringify(data.area.topRect)}.`);
if (this.changeTopAvoidArea()) {
execDispatch(WindowAction.refresh());
}
});
} catch (err) {
HiLog.e(TAG, `initAvoidArea err: ${err}.`);
}
}
private orientationToWindowDirection(orientation: window.Orientation): WindowDirection {
let baseLineDirection: WindowDirection = WindowDirection.TOP;
switch (orientation) {
case window.Orientation.PORTRAIT:
baseLineDirection = WindowDirection.TOP;
break;
case window.Orientation.LANDSCAPE_INVERTED:
baseLineDirection = WindowDirection.RIGHT;
break;
case window.Orientation.PORTRAIT_INVERTED:
baseLineDirection = WindowDirection.BOTTOM;
break;
case window.Orientation.LANDSCAPE:
baseLineDirection = WindowDirection.LEFT;
break;
default:
break;
}
return baseLineDirection;
}
private changeTopAvoidArea(): boolean {
const empty: window.Rect = {
left: 0,
top: 0,
width: 0,
height: 0
};
const cutoutTopRect: window.Rect = !!this.cutoutAvoidArea ? this.cutoutAvoidArea.topRect : empty;
let topAvoidArea = Math.round(px2vp(cutoutTopRect.top + cutoutTopRect.height));
if (topAvoidArea === 0) {
topAvoidArea = 24;
}
if (AdaptiveLayoutService.getInstance().getTopAvoidArea() === topAvoidArea) {
return false;
}
HiLog.i(TAG, `changeTopAvoidArea, topAvoidArea: ${topAvoidArea}.`);
AdaptiveLayoutService.getInstance().setTopAvoidArea(topAvoidArea);
execDispatch(WindowAction.changeTopAvoidArea(topAvoidArea));
return true;
}
private clearTimer(): void {
if (Number.MIN_VALUE !== this.timerId) {
clearTimeout(this.timerId);
this.timerId = Number.MIN_VALUE;
}
}
public lockXComponentSurface(): void {
HiLog.i(TAG, 'lock xComponent surface rotation.');
XComponentService.getInstance().lockSurface(true);
this.isLocked = true;
this.clearTimer();
this.timerId = setTimeout((): void => {
this.timerId = Number.MIN_VALUE;
this.setWinOrientation(window.Orientation.FOLLOW_DESKTOP);
}, 500);
}
public unlockXComponentSurface(): void {
HiLog.i(TAG, 'unlock xComponent surface rotation.');
this.clearTimer();
this.setWinOrientation(window.Orientation.FOLLOW_DESKTOP);
XComponentService.getInstance().lockSurface(false);
this.isLocked = false;
}
public xComponentIsLocked(): boolean {
return this.isLocked;
}
public getWindowStatus(): window.WindowStatusType {
if (this.windowStatus === undefined) {
this.windowStatus = window.WindowStatusType.FULL_SCREEN;
HiLog.i(TAG, 'getWindowStatus is undefined, return FULL_SCREEN.');
}
return this.windowStatus;
}
public getWindowVisibilityStatus(): boolean {
return this.windowVisibilityStatus;
}
* 设置主窗口全屏模式时导航栏显示和隐藏, 欢迎页和引导页未加载时,设置效果为常显
* @param state 'true' | 'false' 显示|隐藏
* @param animation 'true' | 'false' 打开动效|关闭动效
* @param keepConstantDisplay 'true' | 'false' 是否保持常显
* 当前规格:三键时常显,AIBar时维持原来规格。部分界面常显
*/
public setSpecificSystemNavigationEnabled(state: boolean, animation: boolean, keepConstantDisplay: boolean): void {
HiLog.i(TAG, `setSpecificSystemNavigationEnabled trigger. ${state}-${animation}-${keepConstantDisplay}`);
this.aiBarStyle.state = state;
this.aiBarStyle.animation = animation;
this.aiBarStyle.keepConstantDisplay = keepConstantDisplay;
if (this.navigationStyle !== NavigationStyle.AI_BAR && !GlobalContext.get().getT('isSecurityCamera')) {
HiLog.i(TAG, 'setSpecificSystemNavigationEnabled return because is not AI bar.');
this.setNavigationBarAlwaysShow();
return;
}
if (!this.isGuidanceLoaded() && !GlobalContext.get().getIsPicker()) {
this.mWindow?.setSpecificSystemBarEnabled('navigationIndicator', true, false).then(() => {
HiLog.e(TAG, 'setSpecificSystemBarEnabled navigation default success.');
}).catch((err) => {
HiLog.e(TAG, `setSpecificSystemBarEnabled err. ${err?.code}`);
});
return;
}
if (state && !keepConstantDisplay) {
this.mWindow?.setSpecificSystemBarEnabled('navigationIndicator', false, animation).then(() => {
HiLog.i(TAG, `setSpecificSystemBarEnabled navigation - ${false} success. keepConstantDisplay is false`);
}).catch((err) => {
HiLog.e(TAG, `setSpecificSystemBarEnabled err. ${err?.code}`);
});
return;
}
this.mWindow?.setSpecificSystemBarEnabled('navigationIndicator', state, animation).then(() => {
HiLog.i(TAG, `setSpecificSystemBarEnabled navigation - ${state} success1.`);
}).catch((err) => {
HiLog.i(TAG, `setSpecificSystemBarEnabled err1. ${err?.code}`);
});
}
* 设置三键导航时常显
*/
private setNavigationBarAlwaysShow(): void {
this.mWindow?.setSpecificSystemBarEnabled('navigationIndicator', true, true).then(() => {
HiLog.i(TAG, 'setNavigationBarAlwaysShow - true success.');
}).catch((err) => {
HiLog.i(TAG, `setNavigationBarAlwaysShow err. ${err?.code}`);
});
}
* 获取导航栏类型
*/
private initNavigationStyle(): NavigationStyle {
let flag: NavigationStyle = NavigationStyle.AI_BAR;
flag = SettingsValueUtil
.getValueSync('floatingNavigation', '1', settings.domainName.USER_PROPERTY) as NavigationStyle;
HiLog.d(TAG, `initNavigationStyle ${flag}`);
return flag;
}
* 处理导航栏类型变化
*/
private dealWithNavigationStyleChange(): void {
HiLog.d(TAG, `dealWithNavigationStyleChange ${this.navigationStyle}`);
const flag: string = settings.getValueSync(
ContextManager.getInstance().getAbilityContext(), 'floatingNavigation', '1', settings.domainName.USER_PROPERTY);
HiLog.d(TAG, `dealWithNavigationStyleChange: ${flag}`);
if (flag === this.navigationStyle) {
return;
}
this.navigationStyle = flag as NavigationStyle;
if (this.navigationStyle === NavigationStyle.AI_BAR) {
HiLog.d(TAG, `aibar style ${this.aiBarStyle.state},${this.aiBarStyle.animation},
${this.aiBarStyle.keepConstantDisplay}`);
this.setSpecificSystemNavigationEnabled(
this.aiBarStyle.state,
this.aiBarStyle.animation,
this.aiBarStyle.keepConstantDisplay);
} else {
this.setNavigationBarAlwaysShow();
}
}
* 欢迎页和引导页是否已加载完成
* @returns
*/
public isGuidanceLoaded(): boolean {
const instance = PreferencesService.getInstance();
if (!instance.getPublicValue(PersistType.FOREVER, PublicTag.IS_INTRO_LOADED, false) as boolean) {
return false;
}
if (!instance.getPublicValue(PersistType.FOREVER, PublicTag.IS_GUIDANCE_LOADED, false) as boolean) {
return false;
}
return true;
}
* 锁定旋转时是否需要订阅 全局的direction和settingAngle
* @returns
*/
public isSubscriptionNeeded(): boolean {
let windowStatus: window.WindowStatusType = WindowService.getInstance().getWindowStatus();
const direction = getStates().get<WindowDirection>('contextReducer', 'direction');
const isShowLandscape = getStates().get<boolean>('collapsReducer', 'isShowLandscape');
const isShowSemiCollapsed = getStates().get<boolean>('collapsReducer', 'isShowSemiCollapsed');
return direction !== WindowDirection.BOTTOM && (!isShowLandscape || isShowSemiCollapsed) &&
this.accelerometerStatus === '1' && windowStatus !== window.WindowStatusType.FLOATING &&
windowStatus !== window.WindowStatusType.SPLIT_SCREEN;
}
public getWindowAndXComDiffer(winSize: number, xCompSize: number): number {
let differNum = winSize - xCompSize;
if (differNum < DIFFER_TOLERANCE) {
differNum = 0;
}
return differNum;
}
public async setWaterMarkFlag(): Promise<void> {
if (this.isSetWaterMarkFlag) {
await this.mWindow.setWaterMarkFlag(false).then(() => {
HiLog.i(TAG, 'WaterMark is close');
}).catch(error => {
HiLog.i(TAG, `Failed to Set Watermark: ${error.message}`);
});
this.isSetWaterMarkFlag = false;
HiLog.i(TAG, 'WaterMarkFlag : true -> false');
return;
}
HiLog.i(TAG, 'WaterMarkFlag : false -> false');
return;
}
private async onPhotoBrowserStatusChange(data: PhotoBrowserStatusData): Promise<void> {
if (data.photoBrowserStatus && this.isSetWaterMarkFlag) {
await this.mWindow.setWaterMarkFlag(false);
this.isSetWaterMarkFlag = false;
}
}
public setWindowDecorVisiblePc(isVisible: boolean): void {
this.mWindow.setWindowDecorVisible(isVisible);
this.mWindow.setWindowDecorHeight(WIN_DECOR_HEIGHT);
let colorMode: ConfigurationConstant.ColorMode = ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
let style: window.DecorButtonStyle = {
colorMode: colorMode,
buttonBackgroundSize: 28,
spacingBetweenButtons: 12,
closeButtonRightMargin: 20
};
this.mWindow.setDecorButtonStyle(style);
}
public setDecorButtonStyle(isNoSetColorMode: Boolean): void {
let colorMode: ConfigurationConstant.ColorMode =
isNoSetColorMode ? ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET :
ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
this.mWindow.setWindowTitleButtonVisible(true, true, true);
let style: window.DecorButtonStyle = {
colorMode: colorMode,
buttonBackgroundSize: 28,
spacingBetweenButtons: 12,
closeButtonRightMargin: 20
};
this.mWindow.setDecorButtonStyle(style);
}
}