* 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 { CheckEmptyUtils, LogDomain, LogHelper } from '@ohos/basicutils';
import { CheckGridReq, GridOccupyStatusEnum } from '@ohos/componentdrag/src/main/ets/service/reorder/GridOccupyStatus';
import { CellAndSpan, CellLayoutDragDelegate, GridOccupyStatus } from '@ohos/componentdrag/src/main/ets/TsIndex';
import { DefaultDesktopLayoutInfo, GridLayoutItemInfo, SCBHiSysEventUtil } from '../TsIndex';
import { EmptyGridInfoBean } from './ReportParams';
const TAG = 'ReportEmptyGridUtil';
const log: LogHelper = LogHelper.getLogHelper(LogDomain.HOME, TAG);
export class Grid {
public x: number = 0;
public y: number = 0;
public area: number[] = [];
public sum: number = 0;
}
* 桌面_网格报告(状态点,周报,周日报)
*/
export class ReportEmptyGridUtil {
* 桌面_网格报告
*/
public static reportEmptyGridInfo(info: DefaultDesktopLayoutInfo, dragDelegate: CellLayoutDragDelegate): void {
let infos: EmptyGridInfoBean[] = [];
for (let pageIndex = 0; pageIndex < info.layoutDescription.pageCount; pageIndex++) {
let pageItems: GridLayoutItemInfo[] = info.layoutInfo.filter(item => item.page === pageIndex);
let gridOccupyStatus: GridOccupyStatus = dragDelegate.getGridOccupyStatus(pageItems);
let list: EmptyGridInfoBean[] = ReportEmptyGridUtil.buildGridInfo(pageIndex, gridOccupyStatus);
if (!CheckEmptyUtils.isEmptyArr(list)) {
for (let one of list) {
infos.push(one);
}
}
}
SCBHiSysEventUtil.reportEmptyGridInfo(infos);
}
* 根据网格数据构造矩形数据
* 遍历每一行,处理脏数据,可能存在U,这些数据改为O
* 先将 F -> U,构造返回空网格数据
* 再将 O -> U,构造返回非空网格数据
* @param page 页数
* @param gridOccupyStatus 网格数据
* @returns
*/
private static buildGridInfo(page: number, gridOccupyStatus: GridOccupyStatus): EmptyGridInfoBean[] {
let emptyGridInfos: EmptyGridInfoBean[] = [];
if (CheckEmptyUtils.isEmpty(gridOccupyStatus) || CheckEmptyUtils.isEmptyArr(gridOccupyStatus.mStatus)) {
return emptyGridInfos;
}
ReportEmptyGridUtil.checkDirtyData(gridOccupyStatus);
let checkReq: CheckGridReq = {
startCellX: 0,
startCellY: 0,
spanX: gridOccupyStatus.getSizeX(),
spanY: gridOccupyStatus.getSizeY(),
status: GridOccupyStatusEnum.FREE
};
ReportEmptyGridUtil.buildGrid(page, gridOccupyStatus, checkReq, emptyGridInfos);
checkReq.status = GridOccupyStatusEnum.OCCUPIED;
ReportEmptyGridUtil.buildGrid(page, gridOccupyStatus, checkReq, emptyGridInfos);
return emptyGridInfos;
}
* 遍历每一行,处理脏数据,可能存在U,这些数据改为O
*/
private static checkDirtyData(gridOccupyStatus: GridOccupyStatus): void {
let m = gridOccupyStatus.getSizeX();
let n = gridOccupyStatus.getSizeY();
for (let row = 0; row < m; row++) {
for (let col = 0; col < n; col++) {
if (gridOccupyStatus.getStatus(row, col) === GridOccupyStatusEnum.UNKNOWN) {
gridOccupyStatus.markStatus(row, col, GridOccupyStatusEnum.OCCUPIED);
}
}
}
}
* 为了减少数据量,采取每次只获取最大的矩形
*/
private static buildGrid(page: number, gridOccupyStatus: GridOccupyStatus, checkReq: CheckGridReq,
emptyGridInfos: EmptyGridInfoBean[]): void {
let count = 0;
let maxCount = gridOccupyStatus.getSizeX() * gridOccupyStatus.getSizeY();
while (gridOccupyStatus.checkHasStatusForGrid(checkReq)) {
count++;
if (count > maxCount) {
break;
}
let grid: Grid | null = ReportEmptyGridUtil.maximalRectangle(gridOccupyStatus, checkReq.status);
if (!grid) {
break;
}
let cellToSetup: CellAndSpan = new CellAndSpan(grid.x, grid.y, grid.area[0], grid.area[1]);
gridOccupyStatus.markGridForCellAndSpan(cellToSetup, GridOccupyStatusEnum.UNKNOWN);
emptyGridInfos.push(ReportEmptyGridUtil.convertInfo(grid, page, checkReq.status));
}
}
private static convertInfo(grid: Grid, page: number, status: GridOccupyStatusEnum): EmptyGridInfoBean {
let target = new EmptyGridInfoBean();
target.SCREENID = page;
target.SIZE = grid.area[0] + '*' + grid.area[1];
target.CELLX = grid.x;
target.CELLY = grid.y;
target.EMPTYFLAG = status === GridOccupyStatusEnum.FREE ? 1 : 0;
return target;
}
* 查询最大矩形
*
* @param gridOccupyStatus [{'O','O','F','O','O','O'},{'O','O','F','O','O','O'},{'O','O','F','O','O','O'},{'O','O','F','O','O','O'}]
* @param status GridOccupyStatusEnum
* @returns
*/
private static maximalRectangle(gridOccupyStatus: GridOccupyStatus, status: GridOccupyStatusEnum): Grid | null {
let res: Grid | null = null;
try {
let m = gridOccupyStatus.getSizeX();
let n = gridOccupyStatus.getSizeY();
let width = new Array<Array<number>>(m);
for (let i = 0; i < m; ++i) {
width[i] = new Array<number>(n);
width[i].fill(0, 0, n);
}
let maxArea: number = 0;
for (let row = 0; row < m; row++) {
for (let col = 0; col < n; col++) {
if (gridOccupyStatus.getStatus(row, col) === status) {
if (col === 0) {
width[row][col] = 1;
} else {
width[row][col] = width[row][col - 1] + 1;
}
} else {
width[row][col] = 0;
}
let minWidth: number = width[row][col];
for (let up_row = row; up_row >= 0; up_row--) {
let height = row - up_row + 1;
minWidth = Math.min(minWidth, width[up_row][col]);
let tempRectangle = height * minWidth;
if (tempRectangle > maxArea) {
let one = new Grid();
one.y = (col - minWidth + 1);
one.x = (row - height + 1);
one.sum = (tempRectangle);
one.area = [height, minWidth];
res = one;
}
maxArea = Math.max(maxArea, tempRectangle);
}
}
}
} catch (error) {
log.showError(`maximalRectangle failed, error code: ${error.code}, message: ${error.message}.`);
}
return res;
}
}