* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const windowenv = requireInternal('windowenv');
const hilog = requireInternal('hilog');
const HILOG_DOMAIN = 0x04209;
const HILOG_TAG = 'WMSImms';
interface UIEnvAvoidArea {
statusBar: window.AvoidArea;
cutout: window.AvoidArea;
keyboard: window.AvoidArea;
navigationIndicator: window.AvoidArea;
}
enum AvoidAreaType {
TYPE_SYSTEM = 0,
TYPE_CUTOUT = 1,
TYPE_SYSTEM_GESTURE = 2,
TYPE_KEYBOARD = 3,
TYPE_NAVIGATION_INDICATOR = 4,
}
function createEmptyRect(): window.Rect {
return { left: 0, top: 0, width: 0, height: 0 };
}
function createEmptyAvoidArea(): window.AvoidArea {
return {
visible: false,
leftRect: createEmptyRect(),
topRect: createEmptyRect(),
rightRect: createEmptyRect(),
bottomRect: createEmptyRect(),
}
}
@ObservedV2
class WindowAvoidAreaPxEnv implements IEnvironmentValue<UIEnvAvoidArea> {
@Trace statusBar: window.AvoidArea;
@Trace cutout: window.AvoidArea;
@Trace keyboard: window.AvoidArea;
@Trace navigationIndicator: window.AvoidArea;
#win: window.Window | uiExtension.WindowProxy;
get value() {
return this;
}
constructor(context: UIContext) {
try {
this.#win = windowenv.findWindowById(context.getId());
this.statusBar = this.#win.getWindowAvoidArea(AvoidAreaType.TYPE_SYSTEM);
this.cutout = this.#win.getWindowAvoidArea(AvoidAreaType.TYPE_CUTOUT);
this.keyboard = this.#win.getWindowAvoidArea(AvoidAreaType.TYPE_KEYBOARD);
this.navigationIndicator = this.#win.getWindowAvoidArea(AvoidAreaType.TYPE_NAVIGATION_INDICATOR);
this.#win.on('avoidAreaChange', this.#avoidAreaChangeCallback);
} catch (error) {
hilog.error(HILOG_DOMAIN, HILOG_TAG, `[env] px env constructor failed, ${error.message}`);
}
}
#avoidAreaChangeCallback = ({ type, area }: window.AvoidAreaOptions) => {
switch (type) {
case AvoidAreaType.TYPE_SYSTEM:
this.statusBar = area;
break;
case AvoidAreaType.TYPE_CUTOUT:
this.cutout = area;
break;
case AvoidAreaType.TYPE_KEYBOARD:
this.keyboard = area;
break;
case AvoidAreaType.TYPE_NAVIGATION_INDICATOR:
this.navigationIndicator = area;
break;
}
};
update() {}
destroy(): void {
try {
this.#win.off('avoidAreaChange', this.#avoidAreaChangeCallback);
} catch (error) {
hilog.error(HILOG_DOMAIN, HILOG_TAG, `[env] px env destroy failed, ${error.message}`);
}
}
}
@ObservedV2
class WindowAvoidAreaVpEnv implements IEnvironmentValue<UIEnvAvoidArea> {
@Trace statusBar: window.AvoidArea;
@Trace cutout: window.AvoidArea;
@Trace keyboard: window.AvoidArea;
@Trace navigationIndicator: window.AvoidArea;
#win: window.Window | uiExtension.WindowProxy;
#context: UIContext;
#areaInPx: Map<AvoidAreaType, window.AvoidArea> = new Map();
get value() {
return this;
}
constructor(context: UIContext) {
try {
this.#context = context;
this.#win = windowenv.findWindowById(context.getId());
for (const type of [AvoidAreaType.TYPE_SYSTEM, AvoidAreaType.TYPE_CUTOUT, AvoidAreaType.TYPE_KEYBOARD, AvoidAreaType.TYPE_NAVIGATION_INDICATOR]) {
this.#areaInPx.set(type, this.#win.getWindowAvoidArea(type));
}
this.update();
this.#win.on('avoidAreaChange', this.#avoidAreaChangeCallback);
this.#context.getUIObserver().on('densityUpdate', this.#densityUpdateCallback);
} catch (error) {
hilog.error(HILOG_DOMAIN, HILOG_TAG, `[env] vp env constructor failed, ${error.message}`);
}
}
#translateRectToVp(rect: window.Rect): window.Rect {
const vpRect = createEmptyRect();
vpRect.left = this.#context?.px2vp(rect.left) ?? rect.left;
vpRect.top = this.#context?.px2vp(rect.top) ?? rect.top;
vpRect.width = this.#context?.px2vp(rect.width) ?? rect.width;
vpRect.height = this.#context?.px2vp(rect.height) ?? rect.height;
return vpRect;
}
#translateAvoidAreaToVp(area: window.AvoidArea): window.AvoidArea {
const vpArea = createEmptyAvoidArea();
vpArea.visible = area.visible;
vpArea.leftRect = this.#translateRectToVp(area.leftRect);
vpArea.topRect = this.#translateRectToVp(area.topRect);
vpArea.rightRect = this.#translateRectToVp(area.rightRect);
vpArea.bottomRect = this.#translateRectToVp(area.bottomRect);
return vpArea;
}
#avoidAreaChangeCallback = ({ type, area }: window.AvoidAreaOptions) => {
this.#areaInPx.set(type, area);
switch (type) {
case AvoidAreaType.TYPE_SYSTEM:
this.statusBar = this.#translateAvoidAreaToVp(area);
break;
case AvoidAreaType.TYPE_CUTOUT:
this.cutout = this.#translateAvoidAreaToVp(area);
break;
case AvoidAreaType.TYPE_KEYBOARD:
this.keyboard = this.#translateAvoidAreaToVp(area);
break;
case AvoidAreaType.TYPE_NAVIGATION_INDICATOR:
this.navigationIndicator = this.#translateAvoidAreaToVp(area);
break;
}
};
#densityUpdateCallback = () => {
this.update();
}
update() {
if (!this.#context) {
return;
}
if (this.#areaInPx.has(AvoidAreaType.TYPE_SYSTEM)) {
this.statusBar = this.#translateAvoidAreaToVp(this.#areaInPx.get(AvoidAreaType.TYPE_SYSTEM));
}
if (this.#areaInPx.has(AvoidAreaType.TYPE_CUTOUT)) {
this.cutout = this.#translateAvoidAreaToVp(this.#areaInPx.get(AvoidAreaType.TYPE_CUTOUT));
}
if (this.#areaInPx.has(AvoidAreaType.TYPE_KEYBOARD)) {
this.keyboard = this.#translateAvoidAreaToVp(this.#areaInPx.get(AvoidAreaType.TYPE_KEYBOARD));
}
if (this.#areaInPx.has(AvoidAreaType.TYPE_NAVIGATION_INDICATOR)) {
this.navigationIndicator = this.#translateAvoidAreaToVp(
this.#areaInPx.get(AvoidAreaType.TYPE_NAVIGATION_INDICATOR)
);
}
}
destroy(): void {
try {
this.#areaInPx.clear();
this.#context.getUIObserver().off('densityUpdate', this.#densityUpdateCallback);
this.#win.off('avoidAreaChange', this.#avoidAreaChangeCallback);
} catch (error) {
hilog.error(HILOG_DOMAIN, HILOG_TAG, `[env] vp env destroy failed, ${error.message}`);
}
}
}
export default {
WindowAvoidAreaPxEnv,
WindowAvoidAreaVpEnv
}