• 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    if (event === EventConstants.EVENT_PACKAGE_REMOVED) {
150      this.removeItem(bundleName);
151      this.mFormModel.deleteFormByBundleName(bundleName);
152
153      // delete app from folder
154      localEventManager.sendLocalEventSticky(EventConstants.EVENT_FOLDER_PACKAGE_REMOVED, bundleName);
155
156      // delete app form dock
157      localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, {
158        bundleName: bundleName,
159        keyName: undefined
160      });
161      localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RECENT_DOCK_ITEM_DELETE, {
162        bundleName: bundleName,
163        keyName: undefined
164      });
165
166      // delete app from pageDesktop
167      localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_ITEM_DELETE, {
168        bundleName: bundleName,
169        keyName: undefined
170      });
171    } else {
172      const abilityInfos = await launcherAbilityManager.getLauncherAbilityInfo(bundleName);
173      Log.showDebug(TAG, `installationSubscriberCallBack abilityInfos: ${JSON.stringify(abilityInfos)}`);
174      if (!CheckEmptyUtils.isEmptyArr(abilityInfos)){
175        this.replaceItem(bundleName, abilityInfos);
176      }
177      if (event === EventConstants.EVENT_PACKAGE_CHANGED) {
178        await this.getAppListAsync();
179        localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_ITEM_UPDATE, null);
180        localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_UPDATE, abilityInfos[0]);
181      }
182    }
183    this.notifyAppStateChangeEvent();
184  }
185
186  /**
187   * Send event about application state change.
188   */
189  private notifyAppStateChangeEvent() {
190    for (let i = 0; i < this.mAppStateChangeListener.length; i++) {
191      this.mAppStateChangeListener[i](this.mBundleInfoList);
192    }
193  }
194
195  /**
196   * Get the app index in bundleInfoList.
197   *
198   * @param {string} bundleName
199   * @return {number} index
200   */
201  private getItemIndex(bundleName): number {
202    for (const listItem of this.mBundleInfoList) {
203      if (listItem.bundleName === bundleName) {
204        const index = this.mBundleInfoList.indexOf(listItem);
205        return index;
206      }
207    }
208    return CommonConstants.INVALID_VALUE;
209  }
210
211  /**
212   * Append app items into the bundleInfoList.
213   *
214   * @param {array} abilityInfos
215   */
216  private appendItem(abilityInfos): void {
217    for (let index = 0; index < abilityInfos.length; index++) {
218      this.mBundleInfoList.push(abilityInfos[index]);
219    }
220  }
221
222  /**
223   * Remove app item from the bundleInfoList.
224   *
225   * @param {string} bundleName
226   */
227  private removeItem(bundleName: string): void {
228    Log.showDebug(TAG, `removeItem bundleName: ${bundleName}`);
229    let originItemIndex = this.getItemIndex(bundleName);
230    while (originItemIndex != CommonConstants.INVALID_VALUE) {
231      this.removeItemCache(this.mBundleInfoList[originItemIndex]);
232      this.mBundleInfoList.splice(originItemIndex, 1);
233      originItemIndex = this.getItemIndex(bundleName);
234    }
235  }
236
237  /**
238 * Remove app item from the cache.
239 *
240 * @param {string} bundleName
241 */
242  private removeItemCache(appItemInfo: AppItemInfo): void {
243    Log.showDebug(TAG, `removeItemCache bundleName: ${(appItemInfo.bundleName)}`);
244    let cacheKey = appItemInfo.appLabelId + appItemInfo.bundleName + appItemInfo.moduleName;
245    globalThis.ResourceManager.deleteAppResourceCache(cacheKey, 'name');
246    cacheKey = appItemInfo.appIconId + appItemInfo.bundleName + appItemInfo.moduleName;
247    globalThis.ResourceManager.deleteAppResourceCache(cacheKey, 'icon');
248  }
249
250  /**
251   * Replace app items in the bundleInfoList.
252   *
253   * @param {string} bundleName
254   * @param {array} abilityInfos
255   */
256  private replaceItem(bundleName: string, abilityInfos): void {
257    Log.showDebug(TAG, `replaceItem bundleName: ${bundleName}`);
258    this.removeItem(bundleName);
259    this.appendItem(abilityInfos);
260  }
261
262  /**
263   * Put shortcut info into map.
264   *
265   * @param {string} bundleName
266   * @param {array} shortcutInfo
267   */
268  setShortcutInfo(bundleName: string, shortcutInfo: ShortcutInfo[]): void {
269    this.mShortcutInfoMap.set(bundleName, shortcutInfo);
270  }
271
272  /**
273   * Get shortcut info from map.
274   *
275   * @param {string} bundleName
276   * @return {array | undefined} shortcutInfo
277   */
278  getShortcutInfo(bundleName: string): ShortcutInfo[] | undefined {
279    return this.mShortcutInfoMap.get(bundleName);
280  }
281
282  /**
283   * Update shortcut info of map.
284   *
285   * @param {string} bundleName
286   * @param {string | undefined} eventType
287   */
288  private updateShortcutInfo(bundleName, eventType?): void {
289    if (eventType && eventType === EventConstants.EVENT_PACKAGE_REMOVED) {
290      this.mShortcutInfoMap.delete(bundleName);
291      return;
292    }
293    launcherAbilityManager.getShortcutInfo(bundleName, this.setShortcutInfo.bind(this));
294  }
295
296  /**
297   * Close popup.
298   */
299  private closePopup(): void {
300    ContextMenu.close();
301  }
302}