1/* 2 * Copyright (c) 2022-2023 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 bundleMgr from '@ohos.bundle' 17import launcherBundleManager from '@ohos.bundle.launcherBundleManager'; 18import bundleMonitor from '@ohos.bundle.bundleMonitor'; 19import osAccount from '@ohos.account.osAccount' 20import { AppItemInfo } from '../bean/AppItemInfo' 21import { CheckEmptyUtils } from '../utils/CheckEmptyUtils' 22import { CommonConstants } from '../constants/CommonConstants' 23import { EventConstants } from '../constants/EventConstants' 24import { ResourceManager } from './ResourceManager' 25import { Logger } from '../utils/Logger' 26 27const TAG: string = 'LauncherAbilityManager' 28 29/** 30 * Wrapper class for innerBundleManager and formManager interfaces. 31 */ 32export class LauncherAbilityManager { 33 private static readonly BUNDLE_STATUS_CHANGE_KEY_REMOVE = 'remove' 34 private static readonly BUNDLE_STATUS_CHANGE_KEY_ADD = 'add' 35 private static launcherAbilityManager: LauncherAbilityManager = undefined 36 private readonly mAppMap = new Map<string, AppItemInfo>() 37 private mResourceManager: ResourceManager = undefined 38 private readonly mLauncherAbilityChangeListeners: any[] = [] 39 private mUserId: number = 100 40 private context: any = undefined 41 42 constructor(context) { 43 this.context = context 44 this.mResourceManager = ResourceManager.getInstance(context) 45 const osAccountManager = osAccount.getAccountManager() 46 osAccountManager.getOsAccountLocalIdFromProcess((err, localId) => { 47 Logger.debug(TAG, `getOsAccountLocalIdFromProcess localId ${localId}`) 48 this.mUserId = localId 49 }) 50 } 51 52 /** 53 * Get the application data model object. 54 * 55 * @return {object} application data model singleton 56 */ 57 static getInstance(context): LauncherAbilityManager { 58 if (this.launcherAbilityManager === null || this.launcherAbilityManager === undefined) { 59 this.launcherAbilityManager = new LauncherAbilityManager(context) 60 } 61 return this.launcherAbilityManager 62 } 63 64 /** 65 * get all app List info from BMS 66 * 67 * @return 应用的入口Ability信息列表 68 */ 69 async getLauncherAbilityList(): Promise<AppItemInfo[]> { 70 Logger.info(TAG, 'getLauncherAbilityList begin') 71 let abilityList = await launcherBundleManager.getAllLauncherAbilityInfo(this.mUserId) 72 const appItemInfoList = new Array<AppItemInfo>() 73 if (CheckEmptyUtils.isEmpty(abilityList)) { 74 Logger.info(TAG, 'getLauncherAbilityList Empty') 75 return appItemInfoList 76 } 77 for (let i = 0; i < abilityList.length; i++) { 78 let appItem = await this.transToAppItemInfo(abilityList[i]) 79 appItemInfoList.push(appItem) 80 } 81 return appItemInfoList 82 } 83 84 /** 85 * get AppItemInfo from BMS with bundleName 86 * @params bundleName 87 * @return AppItemInfo 88 */ 89 async getAppInfoByBundleName(bundleName: string): Promise<AppItemInfo | undefined> { 90 let appItemInfo: AppItemInfo | undefined = undefined 91 // get from cache 92 if (this.mAppMap != null && this.mAppMap.has(bundleName)) { 93 appItemInfo = this.mAppMap.get(bundleName) 94 } 95 if (appItemInfo != undefined) { 96 Logger.info(TAG, `getAppInfoByBundleName from cache: ${JSON.stringify(appItemInfo)}`) 97 return appItemInfo 98 } 99 // get from system 100 let abilityInfos = await launcherBundleManager.getLauncherAbilityInfo(bundleName, this.mUserId) 101 if (abilityInfos == undefined || abilityInfos.length == 0) { 102 Logger.info(TAG, `${bundleName} has no launcher ability`) 103 return undefined 104 } 105 let appInfo = abilityInfos[0] 106 const data = await this.transToAppItemInfo(appInfo) 107 Logger.info(TAG, `getAppInfoByBundleName from BMS: ${JSON.stringify(data)}`) 108 return data 109 } 110 111 private async transToAppItemInfo(info): Promise<AppItemInfo> { 112 const appItemInfo = new AppItemInfo() 113 appItemInfo.appName = await this.mResourceManager.getAppNameSync( 114 info.labelId, info.elementName.bundleName, info.applicationInfo.label 115 ) 116 appItemInfo.isSystemApp = info.applicationInfo.systemApp 117 appItemInfo.isUninstallAble = info.applicationInfo.removable 118 appItemInfo.appIconId = info.iconId 119 appItemInfo.appLabelId = info.labelId 120 appItemInfo.bundleName = info.elementName.bundleName 121 appItemInfo.abilityName = info.elementName.abilityName 122 await this.mResourceManager.updateIconCache(appItemInfo.appIconId, appItemInfo.bundleName) 123 this.mAppMap.set(appItemInfo.bundleName, appItemInfo) 124 return appItemInfo 125 } 126 127 128 /** 129 * 启动应用 130 * 131 * @params paramAbilityName Ability名 132 * @params paramBundleName 应用包名 133 */ 134 startLauncherAbility(paramAbilityName, paramBundleName) { 135 Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`) 136 this.context.startAbility({ 137 bundleName: paramBundleName, 138 abilityName: paramAbilityName 139 }).then(() => { 140 Logger.info(TAG, 'startApplication promise success') 141 }, (err) => { 142 Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`) 143 }) 144 } 145 146 /** 147 * 通过桌面图标启动应用 148 * 149 * @params paramAbilityName Ability名 150 * @params paramBundleName 应用包名 151 */ 152 startLauncherAbilityFromRecent(paramAbilityName, paramBundleName): void { 153 Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`); 154 this.context.startRecentAbility({ 155 bundleName: paramBundleName, 156 abilityName: paramAbilityName 157 }).then(() => { 158 Logger.info(TAG, 'startApplication promise success'); 159 }, (err) => { 160 Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`); 161 }); 162 } 163 164 /** 165 * 卸载应用 166 * 167 * @params bundleName 应用包名 168 * @params callback 卸载回调 169 */ 170 async uninstallLauncherAbility(bundleName: string, callback): Promise<void> { 171 Logger.info(TAG, `uninstallLauncherAbility bundleName: ${bundleName}`) 172 const bundlerInstaller = await bundleMgr.getBundleInstaller() 173 bundlerInstaller.uninstall(bundleName, { 174 userId: this.mUserId, 175 installFlag: 0, 176 isKeepData: false 177 }, (result) => { 178 Logger.info(TAG, `uninstallLauncherAbility result => ${JSON.stringify(result)}`) 179 callback(result) 180 }) 181 } 182 183 /** 184 * 开始监听系统应用状态. 185 * 186 * @params listener 监听对象 187 */ 188 registerLauncherAbilityChangeListener(listener: any): void { 189 if (!CheckEmptyUtils.isEmpty(listener)) { 190 if (this.mLauncherAbilityChangeListeners.length == 0) { 191 bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD, (bundleChangeInfo) => { 192 Logger.debug(TAG, `mBundleStatusCallback add bundleName: ${bundleChangeInfo.bundleName}, 193 userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`) 194 if (this.mUserId === bundleChangeInfo.userId) { 195 this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_ADDED, 196 bundleChangeInfo.bundleName, bundleChangeInfo.userId) 197 } 198 }) 199 bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE, (bundleChangeInfo) => { 200 Logger.debug(TAG, `mBundleStatusCallback remove bundleName: ${bundleChangeInfo.bundleName}, 201 userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`) 202 if (this.mUserId === bundleChangeInfo.userId) { 203 this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_REMOVED, 204 bundleChangeInfo.bundleName, bundleChangeInfo.userId) 205 } 206 AppStorage.Set('isRefresh', true) 207 }) 208 } 209 const index = this.mLauncherAbilityChangeListeners.indexOf(listener) 210 if (index == CommonConstants.INVALID_VALUE) { 211 this.mLauncherAbilityChangeListeners.push(listener) 212 } 213 } 214 } 215 216 /** 217 * 取消监听系统应用状态. 218 * 219 * @params listener 监听对象 220 */ 221 unregisterLauncherAbilityChangeListener(listener: any): void { 222 if (!CheckEmptyUtils.isEmpty(listener)) { 223 const index = this.mLauncherAbilityChangeListeners.indexOf(listener) 224 if (index != CommonConstants.INVALID_VALUE) { 225 this.mLauncherAbilityChangeListeners.splice(index, 1) 226 } 227 if (this.mLauncherAbilityChangeListeners.length == 0) { 228 bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD) 229 bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE) 230 } 231 } 232 } 233 234 private notifyLauncherAbilityChange(event: string, bundleName: string, userId: number): void { 235 for (let index = 0; index < this.mLauncherAbilityChangeListeners.length; index++) { 236 this.mLauncherAbilityChangeListeners[index](event, bundleName, userId) 237 } 238 } 239}