* 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 { LogDomain, LogHelper } from '@ohos/basicutils';
import { HiSysEventUtil, localEventManager, RdbStoreConfig } from '@ohos/frameworkwrapper';
import Account from '@ohos.account.osAccount';
import { SCBOobeManager } from '@ohos/windowscene';
import rdb from '@ohos.data.rdb';
import GridLayoutInfoColumns from '../db/column/GridLayoutInfoColumns';
import { AppItemInfo } from '../bean/AppItemInfo';
import { CommonConstants, DesktopLayoutState } from '../constants/CommonConstants';
import EventConstants from '../constants/EventConstants';
import DefaultDesktopLayoutInfo from '../configs/DefaultDesktopLayoutInfo';
import GridLayoutItemInfo from '../bean/GridLayoutItemInfo';
import RdbTaskPool from '../db/RdbTaskPool';
import { DesktopDataLoader } from '../viewmodel/DesktopDataLoader';
import { GetLayoutInfoFromConfig } from '../layoutconfig/GetLayoutInfoFromConfig';
import { launcherAbilityManager } from '../abilitymanager/LauncherAbilityManager';
const TAG = 'SCBPreviewCheckTool';
const log: LogHelper = LogHelper.getLogHelper(LogDomain.HOME, TAG);
const MAIN_USERID = 100;
* 在首次OOBE未结束前,对桌面首页布局和预制布局首页图标布局进行比对,如果存在不一致情况,进行兜底处理,重新恢复预制布局配置
*/
export class PreviewLayoutCheckTool {
private static mInstance: PreviewLayoutCheckTool;
private msgArr: string[] = [];
* 开始检查之前需要校验的事件参数
*/
private eventSet: Set<string> = new Set<string>();
public constructor() {
this.msgArr = [];
}
public static getInstance(): PreviewLayoutCheckTool {
if (!PreviewLayoutCheckTool.mInstance) {
PreviewLayoutCheckTool.mInstance = new PreviewLayoutCheckTool();
}
return PreviewLayoutCheckTool.mInstance;
}
* 添加校验的事件参数
* @param event
*/
public addPromiseEvent(event: string): void {
this.eventSet.add(event);
}
* 开始检查布局
* @param loadFromConfiguration
* @returns
*/
public async startCheck(loadFromConfiguration: string): Promise<boolean> {
log.showWarn('checkLayoutInOOBE loadFromConfiguration: %{public}s', loadFromConfiguration);
this.eventSet.delete(loadFromConfiguration);
if (this.eventSet.size !== 0) {
this.eventSet.forEach((key) => log.showWarn('checkLayoutInOOBE return. left events:%{public}s', key));
return false;
}
await this.checkLayoutInOOBE();
this.msgArr = [];
return true;
}
private async checkLayoutInOOBE(): Promise<void> {
try {
let userId = await Account.getAccountManager().getOsAccountLocalId();
if (userId !== MAIN_USERID) {
log.showWarn('checkLayoutInOOBE: not main user now');
return;
}
let isEnable: boolean = SCBOobeManager.isEnable();
if (!isEnable) {
return;
}
let isSame: boolean = await this.checkSame();
log.showWarn('checkLayoutInOOBE: isSame: %{public}s, msg: %{public}s', isSame, this.msgArr.join(';'));
if (!isSame) {
HiSysEventUtil.writePreloadLayout(this.msgArr.join(';'));
localEventManager.sendLocalEvent(EventConstants.EVENT_RESTORE_DESKTOP_LAYOUT, undefined);
}
} catch (e) {
log.showError('checkLayoutInOOBE error, code %{public}d, msg %{public}s', e?.code, e?.message);
}
}
* 当前布局跟预制布局比较
* @returns boolean 如果布局一致,true;如果不一致,false
*/
private async checkSame(): Promise<boolean> {
GetLayoutInfoFromConfig.getInstance().clearFinalLayout();
let desktopDataLoader = DesktopDataLoader.getInstance(DesktopLayoutState.HOME_LAUNCHER_MODE);
let defaultLayoutInfoFromFile: DefaultDesktopLayoutInfo = await desktopDataLoader.loadFromJsonConfig();
if (!defaultLayoutInfoFromFile || !defaultLayoutInfoFromFile.layoutInfo) {
return true;
}
let appBundles: string[] = [];
let bmsAppList: AppItemInfo[] = await launcherAbilityManager.getLauncherAbilityList(MAIN_USERID);
bmsAppList?.forEach((item: AppItemInfo) => {
appBundles.push(`${item.bundleName}_${item.abilityName}_${item.moduleName}`);
});
let defaultApps: Set<string> = new Set();
let keys: string[] = [];
defaultLayoutInfoFromFile.layoutInfo.forEach((item: GridLayoutItemInfo) => {
if (item && item.page === 0 && item.typeId === CommonConstants.TYPE_APP &&
item.container === CommonConstants.CONTAINER_DESKTOP &&
appBundles.indexOf(`${item.bundleName}_${item.abilityName}_${item.moduleName}`) !== -1) {
let key = this.getGridLayoutItemInfoKey(item);
defaultApps.add(key);
keys.push(key);
}
});
let defaultMag = `default:${keys.join(',')}`;
log.showWarn(defaultMag);
this.msgArr.push(defaultMag);
return this.compare(defaultApps);
}
private async getFirstPageApp(): Promise<GridLayoutItemInfo[]> {
let conditions: Map<string, rdb.ValueType> = new Map();
conditions.set(GridLayoutInfoColumns.PAGE_INDEX, 0);
conditions.set(GridLayoutInfoColumns.TYPE_ID, CommonConstants.TYPE_APP);
conditions.set(GridLayoutInfoColumns.CONTAINER, CommonConstants.CONTAINER_DESKTOP);
return await RdbTaskPool.getInstance().queryGridLayoutInfo(RdbStoreConfig.gridLayoutInfo.tableName, conditions);
}
* 比较预制布局跟数据库
* @param defaultApps 预制布局
* @returns boolean 如果布局一致,true;如果不一致,false
*/
private async compare(defaultApps: Set<string>): Promise<boolean> {
let currentList: GridLayoutItemInfo[] = await this.getFirstPageApp();
if (!currentList) {
log.showWarn('currentList is empty');
return false;
}
let currentKeys: string[] = [];
currentList.filter(item => item && item.page === 0 && item.typeId === CommonConstants.TYPE_APP)
.forEach((item: GridLayoutItemInfo) => {
let key = this.getGridLayoutItemInfoKey(item);
currentKeys.push(key);
});
let currentMsg = `current:${currentKeys.join(',')}`;
log.showWarn(currentMsg);
this.msgArr.push(currentMsg);
if (currentList.length !== defaultApps.size) {
this.msgArr.push(`size is different. default layout:${defaultApps.size}, current layout:${currentList.length}`);
return false;
}
for (let i = 0; i < currentKeys.length; i++) {
let key = currentKeys[i];
if (!defaultApps.has(key)) {
this.msgArr.push(`default layout do not have:${key}`);
return false;
}
defaultApps.delete(key);
}
if (defaultApps.size > 0) {
let keys: string[] = [];
defaultApps.forEach((key: string) => keys.push(key));
this.msgArr.push(`current layout do not have:${keys.join(';')}`);
return false;
}
log.showWarn('compare first page app layout is same.');
return true;
}
private getGridLayoutItemInfoKey(item: GridLayoutItemInfo): string {
return `${item.bundleName}_${item.abilityName}_${item.moduleName}_${item.container}_${item.page}_${item.row}_${item.column}`;
}
}