• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 { ShortcutInfo } from 'bundle/shortcutInfo';
17import { Log } from '../utils/Log';
18import { CheckEmptyUtils } from '../utils/CheckEmptyUtils';
19import { EventConstants } from '../constants/EventConstants';
20import { CommonConstants } from '../constants/CommonConstants';
21import { FormModel } from './FormModel';
22import { AppItemInfo } from '../bean/AppItemInfo';
23import { localEventManager } from '../manager/LocalEventManager';
24import { launcherAbilityManager } from '../manager/LauncherAbilityManager';
25import SystemApplication from '../configs/SystemApplication';
26
27const TAG = 'AppModel';
28
29/**
30 * Desktop application information data model.
31 */
32export class AppModel {
33  private mBundleInfoList: AppItemInfo[] = [];
34  private readonly mSystemApplicationName = [];
35  private readonly mAppStateChangeListener = [];
36  private readonly mShortcutInfoMap = new Map<string, ShortcutInfo[]>();
37  private readonly mFormModel: FormModel;
38  private readonly mInstallationListener;
39
40  private constructor() {
41    Log.showInfo(TAG, 'constructor start');
42    this.mSystemApplicationName = SystemApplication.SystemApplicationName.split(',');
43    this.mFormModel = FormModel.getInstance();
44    this.mInstallationListener = this.installationSubscriberCallBack.bind(this);
45  }
46
47  /**
48   * Get the application data model object.
49   *
50   * @return {object} application data model singleton
51   */
52  static getInstance(): AppModel {
53    if (globalThis.AppModel == null) {
54      globalThis.AppModel = new AppModel();
55    }
56    return globalThis.AppModel;
57  }
58
59  /**
60   * Get the list of apps displayed on the desktop.
61   * (public function, reduce the frequency of method call)
62   *
63   * @return {array} bundleInfoList
64   */
65  async getAppList() {
66    Log.showInfo(TAG, 'getAppList start');
67    if (!CheckEmptyUtils.isEmptyArr(this.mBundleInfoList)) {
68      Log.showInfo(TAG, `getAppList bundleInfoList length: ${this.mBundleInfoList.length}`);
69      return this.mBundleInfoList;
70    }
71    const bundleInfoList: AppItemInfo[] = await this.getAppListAsync();
72    return bundleInfoList;
73  }
74
75  /**
76   * Get the list of apps displayed on the desktop (private function).
77   *
78   * @return {array} bundleInfoList, excluding system applications
79   */
80  async getAppListAsync(): Promise<AppItemInfo[]> {
81    let allAbilityList: AppItemInfo[] = await launcherAbilityManager.getLauncherAbilityList();
82    Log.showInfo(TAG, `getAppListAsync--->allAbilityList length: ${allAbilityList.length}`);
83    let launcherAbilityList: AppItemInfo[] = [];
84    for (let i in allAbilityList) {
85      if (this.mSystemApplicationName.indexOf(allAbilityList[i].bundleName) === CommonConstants.INVALID_VALUE) {
86        launcherAbilityList.push(allAbilityList[i]);
87        this.updateShortcutInfo(allAbilityList[i].bundleName);
88        this.mFormModel.updateAppItemFormInfo(allAbilityList[i].bundleName);
89      }
90    }
91    this.mBundleInfoList = launcherAbilityList;
92    Log.showInfo(TAG, `getAppListAsync--->allAbilityList length after filtration: ${launcherAbilityList.length}`);
93    return launcherAbilityList;
94  }
95
96  /**
97   * Register application list change event listener.
98   *
99   * @param listener
100   */
101  registerStateChangeListener(listener): void {
102    if (this.mAppStateChangeListener.indexOf(listener) === CommonConstants.INVALID_VALUE) {
103      this.mAppStateChangeListener.push(listener);
104    }
105  }
106
107  /**
108   * Unregister application list change event listener.
109   *
110   * @param listener
111   */
112  unregisterAppStateChangeListener(listener): void {
113    let index: number = this.mAppStateChangeListener.indexOf(listener);
114    if (index != CommonConstants.INVALID_VALUE) {
115      this.mAppStateChangeListener.splice(index, 1);
116    }
117  }
118
119  getUserId(): number {
120    return launcherAbilityManager.getUserId();
121  }
122
123  /**
124   * Start listening to the system application status.
125   */
126  registerAppListEvent(): void {
127    launcherAbilityManager.registerLauncherAbilityChangeListener(this.mInstallationListener);
128  }
129
130  /**
131   * Stop listening for system application status.
132   */
133  unregisterAppListEvent(): void {
134    launcherAbilityManager.unregisterLauncherAbilityChangeListener(this.mInstallationListener);
135  }
136
137  /**
138   * The callback function of the application installation event.
139   *
140   * @param {Object} event
141   * @param {string} bundleName
142   * @param {number} userId
143   */
144  private async installationSubscriberCallBack(event, bundleName, userId) {
145    Log.showInfo(TAG, `installationSubscriberCallBack event: ${event}`);
146    this.closePopup();
147    this.updateShortcutInfo(bundleName, event);
148    this.mFormModel.updateAppItemFormInfo(bundleName, event);
149    // initial mBundleInfoList
150    if (CheckEmptyUtils.isEmptyArr(this.mBundleInfoList)) {
151      await this.getAppListAsync();
152    }
153    if (event === EventConstants.EVENT_PACKAGE_REMOVED) {
154      this.removeItem(bundleName);
155      this.mFormModel.deleteFormByBundleName(bundleName);
156
157      // delete app from folder
158      localEventManager.sendLocalEventSticky(EventConstants.EVENT_FOLDER_PACKAGE_REMOVED, bundleName);
159
160      // delete app form dock
161      localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, {
162        bundleName: bundleName,
163        keyName: undefined
164      });
165      localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RECENT_DOCK_ITEM_DELETE, {
166        bundleName: bundleName,
167        keyName: undefined
168      });
169
170      // delete app from pageDesktop
171      localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_ITEM_DELETE, {
172        bundleName: bundleName,
173        keyName: undefined
174      });
175    } else {
176      const abilityInfos = await launcherAbilityManager.getLauncherAbilityInfo(bundleName);
177      Log.showDebug(TAG, `installationSubscriberCallBack abilityInfos: ${JSON.stringify(abilityInfos)}`);
178      if (!CheckEmptyUtils.isEmptyArr(abilityInfos)){
179        this.replaceItem(bundleName, abilityInfos);
180      }
181      if (event === EventConstants.EVENT_PACKAGE_CHANGED) {
182        await this.getAppListAsync();
183        localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_ITEM_UPDATE, null);
184        localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_UPDATE, abilityInfos[0]);
185      }
186    }
187    this.notifyAppStateChangeEvent();
188  }
189
190  /**
191   * Send event about application state change.
192   */
193  private notifyAppStateChangeEvent() {
194    for (let i = 0; i < this.mAppStateChangeListener.length; i++) {
195      this.mAppStateChangeListener[i](this.mBundleInfoList);
196    }
197  }
198
199  /**
200   * Get the app index in bundleInfoList.
201   *
202   * @param {string} bundleName
203   * @return {number} index
204   */
205  private getItemIndex(bundleName): number {
206    for (const listItem of this.mBundleInfoList) {
207      if (listItem.bundleName === bundleName) {
208        const index = this.mBundleInfoList.indexOf(listItem);
209        return index;
210      }
211    }
212    return CommonConstants.INVALID_VALUE;
213  }
214
215  /**
216   * Append app items into the bundleInfoList.
217   *
218   * @param {array} abilityInfos
219   */
220  private appendItem(abilityInfos): void {
221    for (let index = 0; index < abilityInfos.length; index++) {
222      this.mBundleInfoList.push(abilityInfos[index]);
223    }
224  }
225
226  /**
227   * Remove app item from the bundleInfoList.
228   *
229   * @param {string} bundleName
230   */
231  private removeItem(bundleName: string): void {
232    Log.showDebug(TAG, `removeItem bundleName: ${bundleName}`);
233    let originItemIndex = this.getItemIndex(bundleName);
234    while (originItemIndex != CommonConstants.INVALID_VALUE) {
235      this.removeItemCache(this.mBundleInfoList[originItemIndex]);
236      this.mBundleInfoList.splice(originItemIndex, 1);
237      originItemIndex = this.getItemIndex(bundleName);
238    }
239  }
240
241  /**
242 * Remove app item from the cache.
243 *
244 * @param {string} bundleName
245 */
246  private removeItemCache(appItemInfo: AppItemInfo): void {
247    Log.showDebug(TAG, `removeItemCache bundleName: ${(appItemInfo.bundleName)}`);
248    let cacheKey = appItemInfo.appLabelId + appItemInfo.bundleName + appItemInfo.moduleName;
249    globalThis.ResourceManager.deleteAppResourceCache(cacheKey, 'name');
250    cacheKey = appItemInfo.appIconId + appItemInfo.bundleName + appItemInfo.moduleName;
251    globalThis.ResourceManager.deleteAppResourceCache(cacheKey, 'icon');
252  }
253
254  /**
255   * Replace app items in the bundleInfoList.
256   *
257   * @param {string} bundleName
258   * @param {array} abilityInfos
259   */
260  private replaceItem(bundleName: string, abilityInfos): void {
261    Log.showDebug(TAG, `replaceItem bundleName: ${bundleName}`);
262    this.removeItem(bundleName);
263    this.appendItem(abilityInfos);
264  }
265
266  /**
267   * Put shortcut info into map.
268   *
269   * @param {string} bundleName
270   * @param {array} shortcutInfo
271   */
272  setShortcutInfo(bundleName: string, shortcutInfo: ShortcutInfo[]): void {
273    this.mShortcutInfoMap.set(bundleName, shortcutInfo);
274  }
275
276  /**
277   * Get shortcut info from map.
278   *
279   * @param {string} bundleName
280   * @return {array | undefined} shortcutInfo
281   */
282  getShortcutInfo(bundleName: string): ShortcutInfo[] | undefined {
283    return this.mShortcutInfoMap.get(bundleName);
284  }
285
286  /**
287   * Update shortcut info of map.
288   *
289   * @param {string} bundleName
290   * @param {string | undefined} eventType
291   */
292  private updateShortcutInfo(bundleName, eventType?): void {
293    if (eventType && eventType === EventConstants.EVENT_PACKAGE_REMOVED) {
294      this.mShortcutInfoMap.delete(bundleName);
295      return;
296    }
297    launcherAbilityManager.getShortcutInfo(bundleName, this.setShortcutInfo.bind(this));
298  }
299
300  /**
301   * Close popup.
302   */
303  private closePopup(): void {
304    ContextMenu.close();
305  }
306}