1/** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import installer from '@ohos.bundle.installer'; 17import bundleMonitor from '@ohos.bundle.bundleMonitor'; 18import osAccount from '@ohos.account.osAccount'; 19import hiSysEvent from '@ohos.hiSysEvent'; 20import launcherBundleManager from '@ohos.bundle.launcherBundleManager'; 21import { Log } from '../utils/Log'; 22import { CheckEmptyUtils } from '../utils/CheckEmptyUtils'; 23import { AppItemInfo } from '../bean/AppItemInfo'; 24import { CommonConstants } from '../constants/CommonConstants'; 25import { ResourceManager } from './ResourceManager'; 26import { EventConstants } from '../constants/EventConstants'; 27import { BadgeManager } from '../manager/BadgeManager'; 28import { BusinessError } from '@ohos.base'; 29 30const TAG = 'LauncherAbilityManager'; 31 32interface BundleStatusCallback { 33 add: (bundleName: string, userId: number) => void; 34 remove: (bundleName: string, userId: number) => void; 35 update: (bundleName: string, userId: number) => void; 36} 37 38/** 39 * Wrapper class for innerBundleManager and formManager interfaces. 40 */ 41class LauncherAbilityManager { 42 private static readonly CURRENT_USER_ID = -2; 43 private readonly mAppMap = new Map<string, AppItemInfo>(); 44 private mUserId: number = 100; 45 46 private readonly mBundleStatusCallback: BundleStatusCallback = { 47 add: (bundleName, userId) => { 48 Log.showDebug(TAG, `PACKAGE_ADDED bundleName: ${bundleName}, userId: ${userId}, mUserId ${this.mUserId}`); 49 this.mUserId === userId && this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_ADDED, bundleName, userId); 50 }, 51 remove: (bundleName, userId) => { 52 Log.showDebug(TAG, `PACKAGE_REMOVED bundleName: ${bundleName}, userId: ${userId}, mUserId ${this.mUserId}`); 53 this.mUserId === userId && this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_REMOVED, bundleName, userId); 54 }, 55 update: (bundleName, userId) => { 56 Log.showDebug(TAG, `PACKAGE_CHANGED bundleName: ${bundleName}, userId: ${userId}, mUserId ${this.mUserId}`); 57 this.mUserId === userId && this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_CHANGED, bundleName, userId); 58 } 59 }; 60 61 private readonly mLauncherAbilityChangeListeners: any[] = []; 62 63 /** 64 * Get desktop application information management object 65 * 66 * @return Desktop application information management object instance 67 */ 68 static getInstance(): LauncherAbilityManager { 69 if (globalThis.LauncherAbilityManagerInstance == null) { 70 globalThis.LauncherAbilityManagerInstance = new LauncherAbilityManager(); 71 } 72 return globalThis.LauncherAbilityManagerInstance; 73 } 74 75 private constructor() { 76 const osAccountManager = osAccount.getAccountManager(); 77 osAccountManager.getOsAccountLocalId((err, localId) => { 78 Log.showDebug(TAG, `getOsAccountLocalId localId ${localId}`); 79 this.mUserId = localId; 80 }); 81 } 82 83 getUserId(): number { 84 return this.mUserId; 85 } 86 87 /** 88 * Monitor system application status. 89 * 90 * @params listener: listening object 91 */ 92 registerLauncherAbilityChangeListener(listener: any): void { 93 if (listener != null) { 94 if (this.mLauncherAbilityChangeListeners.length == 0) { 95 try { 96 bundleMonitor.on('add', (bundleChangeInfo) => { 97 Log.showInfo(TAG, `add bundleName: ${bundleChangeInfo.bundleName} userId: ${bundleChangeInfo.userId}`); 98 this.mBundleStatusCallback.add(bundleChangeInfo.bundleName, bundleChangeInfo.userId); 99 }); 100 bundleMonitor.on('update', (bundleChangeInfo) => { 101 Log.showInfo(TAG, `update bundleName: ${bundleChangeInfo.bundleName} userId: ${bundleChangeInfo.userId}`); 102 this.mBundleStatusCallback.update(bundleChangeInfo.bundleName, bundleChangeInfo.userId); 103 }); 104 bundleMonitor.on('remove', (bundleChangeInfo) => { 105 Log.showInfo(TAG, `remove bundleName: ${bundleChangeInfo.bundleName} userId: ${bundleChangeInfo.userId}`); 106 this.mBundleStatusCallback.remove(bundleChangeInfo.bundleName, bundleChangeInfo.userId); 107 }); 108 Log.showInfo(TAG, `registerCallback success`); 109 } catch (errData) { 110 let message = (errData as BusinessError).message; 111 let errCode = (errData as BusinessError).code; 112 Log.showError(TAG, `registerCallback fail errCode:${errCode}, message:${message}`); 113 } 114 } 115 const index = this.mLauncherAbilityChangeListeners.indexOf(listener); 116 if (index == CommonConstants.INVALID_VALUE) { 117 this.mLauncherAbilityChangeListeners.push(listener); 118 } 119 } 120 } 121 122 /** 123 * Cancel monitoring system application status. 124 * 125 * @params listener: listening object 126 */ 127 unregisterLauncherAbilityChangeListener(listener: any): void { 128 if (listener != null) { 129 const index = this.mLauncherAbilityChangeListeners.indexOf(listener); 130 if (index != CommonConstants.INVALID_VALUE) { 131 this.mLauncherAbilityChangeListeners.splice(index, 1); 132 } 133 if (this.mLauncherAbilityChangeListeners.length == 0) { 134 try { 135 bundleMonitor.off('add'); 136 bundleMonitor.off('update'); 137 bundleMonitor.off('remove'); 138 Log.showInfo(TAG, 'unregisterCallback success'); 139 } catch (errData) { 140 let message = (errData as BusinessError).message; 141 let errCode = (errData as BusinessError).code; 142 Log.showError(TAG, `unregisterCallback fail errCode:${errCode}, message:${message}`); 143 } 144 } 145 } 146 } 147 148 private notifyLauncherAbilityChange(event, bundleName: string, userId): void { 149 for (let index = 0; index < this.mLauncherAbilityChangeListeners.length; index++) { 150 this.mLauncherAbilityChangeListeners[index](event, bundleName, userId); 151 } 152 } 153 154 /** 155 * get all app List info from BMS 156 */ 157 async getLauncherAbilityList(): Promise<AppItemInfo[]> { 158 let abilityList = null; 159 await launcherBundleManager.getAllLauncherAbilityInfo(LauncherAbilityManager.CURRENT_USER_ID) 160 .then((res) => { 161 abilityList = res; 162 }) 163 .catch((err) => { 164 Log.showError(TAG, `getLauncherAbilityList error: ${JSON.stringify(err)}`); 165 }); 166 const appItemInfoList = new Array<AppItemInfo>(); 167 if (CheckEmptyUtils.isEmpty(abilityList)) { 168 Log.showDebug(TAG, 'getLauncherAbilityList Empty'); 169 return appItemInfoList; 170 } 171 for (let i = 0; i < abilityList.length; i++) { 172 let appItem = await this.convertToAppItemInfo(abilityList[i]); 173 appItemInfoList.push(appItem); 174 } 175 return appItemInfoList; 176 } 177 178 /** 179 * get AbilityInfos by bundleName from BMS 180 * 181 * @params bundleName Application package name 182 * @return List of entry capabilities information of the target application 183 */ 184 async getLauncherAbilityInfo(bundleName: string): Promise<AppItemInfo[]> { 185 let abilityInfos: launcherBundleManager.LauncherAbilityInfo[]; 186 await launcherBundleManager.getLauncherAbilityInfo(bundleName, this.mUserId) 187 .then((res) => { 188 abilityInfos = res; 189 }) 190 .catch((err) => { 191 Log.showError(TAG, `getLauncherAbilityInfo error: ${JSON.stringify(err)}`); 192 }); 193 const appItemInfoList = new Array<AppItemInfo>(); 194 if (CheckEmptyUtils.isEmpty(abilityInfos) || abilityInfos.length === 0) { 195 Log.showDebug(TAG, 'getLauncherAbilityInfo Empty'); 196 return appItemInfoList; 197 } 198 for (let i = 0; i < abilityInfos.length; i++) { 199 let appItem = await this.convertToAppItemInfo(abilityInfos[i]); 200 appItemInfoList.push(appItem); 201 } 202 return appItemInfoList; 203 } 204 205 /** 206 * get AppItemInfo from BMS with bundleName 207 * @params bundleName 208 * @return AppItemInfo 209 */ 210 async getAppInfoByBundleName(bundleName: string, abilityName?: string): Promise<AppItemInfo | undefined> { 211 let appItemInfo: AppItemInfo | undefined = undefined; 212 // get from cache 213 if (this.mAppMap && this.mAppMap.has(bundleName)) { 214 appItemInfo = this.mAppMap.get(bundleName); 215 } 216 if (appItemInfo && abilityName && appItemInfo.abilityName === abilityName) { 217 return appItemInfo; 218 } 219 // get from system 220 let abilityInfos = new Array<launcherBundleManager.LauncherAbilityInfo>(); 221 await launcherBundleManager.getLauncherAbilityInfo(bundleName, LauncherAbilityManager.CURRENT_USER_ID) 222 .then((res)=>{ 223 if (res && res.length) { 224 abilityInfos = res; 225 } 226 }) 227 .catch((err)=>{ 228 Log.showError(TAG, `getAppInfoByBundleName getLauncherAbilityInfo error: ${JSON.stringify(err)}`); 229 }); 230 if (!abilityInfos || abilityInfos.length === 0) { 231 Log.showDebug(TAG, `${bundleName} has no launcher ability`); 232 return undefined; 233 } 234 let appInfo = abilityInfos[0]; 235 if (abilityName) { 236 appInfo = abilityInfos.find(item => { 237 return item.elementName.abilityName === abilityName; 238 }); 239 } 240 if (!appInfo) { 241 appInfo = abilityInfos[0]; 242 } 243 const data = await this.convertToAppItemInfo(appInfo); 244 return data; 245 } 246 247 private async convertToAppItemInfo(info): Promise<AppItemInfo> { 248 const appItemInfo = new AppItemInfo(); 249 appItemInfo.appName = await ResourceManager.getInstance().getAppNameSync( 250 info.labelId, info.elementName.bundleName, info.elementName.moduleName, info.applicationInfo.label 251 ); 252 appItemInfo.isSystemApp = info.applicationInfo.systemApp; 253 appItemInfo.isUninstallAble = info.applicationInfo.removable; 254 appItemInfo.appIconId = info.iconId; 255 appItemInfo.appLabelId = info.labelId; 256 appItemInfo.bundleName = info.elementName.bundleName; 257 appItemInfo.abilityName = info.elementName.abilityName; 258 appItemInfo.moduleName = info.elementName.moduleName; 259 appItemInfo.keyName = info.elementName.bundleName + info.elementName.abilityName + info.elementName.moduleName; 260 appItemInfo.typeId = CommonConstants.TYPE_APP; 261 appItemInfo.installTime = String(new Date()); 262 appItemInfo.badgeNumber = await BadgeManager.getInstance().getBadgeByBundleSync(info.elementName.bundleName); 263 await ResourceManager.getInstance().updateIconCache(appItemInfo.appIconId, appItemInfo.bundleName, appItemInfo.moduleName); 264 this.mAppMap.set(appItemInfo.bundleName, appItemInfo); 265 return appItemInfo; 266 } 267 268 /** 269 * uninstall application, notice the userId need to be the login user 270 * 271 * @params bundleName application bundleName 272 * @params callback to get result 273 */ 274 async uninstallLauncherAbility(bundleName: string, callback: (resultCode: number) => void): Promise<void> { 275 Log.showInfo(TAG, `uninstallLauncherAbility bundleName: ${bundleName}`); 276 try { 277 const bundlerInstaller = await installer.getBundleInstaller(); 278 bundlerInstaller.uninstall(bundleName, { 279 userId: this.mUserId, 280 installFlag: 0, 281 isKeepData: false 282 }, (err: BusinessError) => { 283 if (err) { 284 callback(CommonConstants.INVALID_VALUE); 285 Log.showError(TAG, `uninstallLauncherAbility failed: ${JSON.stringify(err)}`); 286 } else { 287 callback(CommonConstants.UNINSTALL_SUCCESS); 288 Log.showDebug(TAG, `uninstallLauncherAbility successfully: ${JSON.stringify(err)}`); 289 } 290 }); 291 } catch (err) { 292 let errCode = (err as BusinessError).code; 293 let errMsg = (err as BusinessError).message; 294 Log.showError(TAG, `uninstallLauncherAbility errCode: ${errCode}, errMsg: ${errMsg}`); 295 } 296 } 297 298 /** 299 * start the app 300 * 301 * @params paramAbilityName: Ability name 302 * @params paramBundleName: Application package name 303 */ 304 startLauncherAbility(paramAbilityName: string, paramBundleName: string, paramModuleName: string) { 305 Log.showDebug(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}, moduleName ${paramModuleName}`); 306 globalThis.desktopContext.startAbility({ 307 bundleName: paramBundleName, 308 abilityName: paramAbilityName, 309 moduleName: paramModuleName 310 }).then(() => { 311 Log.showDebug(TAG, 'startApplication promise success'); 312 }, (err) => { 313 Log.showError(TAG, `startApplication promise error: ${JSON.stringify(err)}`); 314 }); 315 316 const sysEventInfo = { 317 domain: 'LAUNCHER_APP', 318 name: 'START_ABILITY', 319 eventType: hiSysEvent.EventType.BEHAVIOR, 320 params: { 321 'BUNDLE_NAME': paramBundleName, 322 'ABILITY_NAME': paramAbilityName, 323 'MODULE_NAME': paramModuleName 324 } 325 }; 326 hiSysEvent.write(sysEventInfo, 327 (err, value) => { 328 if (err) { 329 Log.showError(TAG, `startApplication hiSysEvent write error: ${err.code}`); 330 } else { 331 Log.showDebug(TAG, `startApplication hiSysEvent write success: ${value}`); 332 } 333 }) 334 } 335 336 /** 337 * start form config ability 338 * 339 * @params paramAbilityName 340 * @params paramBundleName 341 */ 342 startAbilityFormEdit(paramAbilityName: string, paramBundleName: string, paramModuleName: string, paramCardId: number) { 343 Log.showDebug(TAG, `startAbility abilityName: ${paramAbilityName},bundleName: ${paramBundleName}, moduleName: ${paramModuleName} ,paramCardId: ${paramCardId}`); 344 globalThis.desktopContext.startAbility({ 345 bundleName: paramBundleName, 346 abilityName: paramAbilityName, 347 moduleName: paramModuleName, 348 parameters: 349 { 350 formId: paramCardId.toString() 351 } 352 }).then((ret) => { 353 Log.showDebug(TAG, `startAbility ret: ${JSON.stringify(ret)}`); 354 }, (err) => { 355 Log.showError(TAG, `startAbility catch error: ${JSON.stringify(err)}`); 356 }); 357 } 358 359 async getShortcutInfo(paramBundleName: string, callback) { 360 Log.showDebug(TAG, `getShortcutInfo bundleName: ${paramBundleName}`); 361 await launcherBundleManager.getShortcutInfo(paramBundleName) 362 .then(shortcutInfo => { 363 callback(paramBundleName, shortcutInfo); 364 }) 365 .catch(err => { 366 }); 367 } 368 369 /** 370 * start application by uri 371 * 372 * @params paramBundleName application bundle name 373 * @params paramAbilityName application abilit uri 374 */ 375 startLauncherAbilityByUri(paramBundleName: string, abilityUri) { 376 Log.showInfo(TAG, `startLauncherAbilityByUri bundleName:${paramBundleName} abilityUri:${abilityUri}`); 377 const result = globalThis.desktopContext.startAbility({ 378 bundleName: paramBundleName, 379 uri: abilityUri 380 }).then(() => { 381 Log.showDebug(TAG, 'startLauncherAbilityByUri promise success'); 382 }, (err) => { 383 Log.showError(TAG, `startLauncherAbilityByUri promise error: ${JSON.stringify(err)}`); 384 }); 385 Log.showDebug(TAG, `startLauncherAbilityByUri AceApplication : startAbility : ${result}`); 386 } 387 388 cleanAppMapCache() { 389 this.mAppMap.clear(); 390 } 391} 392 393export const launcherAbilityManager = LauncherAbilityManager.getInstance(); 394