• 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        AppStorage.SetOrCreate('formRefresh', String(new Date()));
184        localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_ITEM_UPDATE, null);
185        localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_UPDATE, abilityInfos[0]);
186      }
187    }
188    this.notifyAppStateChangeEvent();
189  }
190
191  /**
192   * Send event about application state change.
193   */
194  private notifyAppStateChangeEvent() {
195    for (let i = 0; i < this.mAppStateChangeListener.length; i++) {
196      this.mAppStateChangeListener[i](this.mBundleInfoList);
197    }
198  }
199
200  /**
201   * Get the app index in bundleInfoList.
202   *
203   * @param {string} bundleName
204   * @return {number} index
205   */
206  private getItemIndex(bundleName): number {
207    for (const listItem of this.mBundleInfoList) {
208      if (listItem.bundleName === bundleName) {
209        const index = this.mBundleInfoList.indexOf(listItem);
210        return index;
211      }
212    }
213    return CommonConstants.INVALID_VALUE;
214  }
215
216  /**
217   * Append app items into the bundleInfoList.
218   *
219   * @param {array} abilityInfos
220   */
221  private appendItem(abilityInfos): void {
222    for (let index = 0; index < abilityInfos.length; index++) {
223      this.mBundleInfoList.push(abilityInfos[index]);
224    }
225  }
226
227  /**
228   * Remove app item from the bundleInfoList.
229   *
230   * @param {string} bundleName
231   */
232  private removeItem(bundleName: string): void {
233    Log.showDebug(TAG, `removeItem bundleName: ${bundleName}`);
234    let originItemIndex = this.getItemIndex(bundleName);
235    while (originItemIndex != CommonConstants.INVALID_VALUE) {
236      this.removeItemCache(this.mBundleInfoList[originItemIndex]);
237      this.mBundleInfoList.splice(originItemIndex, 1);
238      originItemIndex = this.getItemIndex(bundleName);
239    }
240  }
241
242  /**
243 * Remove app item from the cache.
244 *
245 * @param {string} bundleName
246 */
247  private removeItemCache(appItemInfo: AppItemInfo): void {
248    Log.showDebug(TAG, `removeItemCache bundleName: ${(appItemInfo.bundleName)}`);
249    let cacheKey = appItemInfo.appLabelId + appItemInfo.bundleName + appItemInfo.moduleName;
250    globalThis.ResourceManager.deleteAppResourceCache(cacheKey, 'name');
251    cacheKey = appItemInfo.appIconId + appItemInfo.bundleName + appItemInfo.moduleName;
252    globalThis.ResourceManager.deleteAppResourceCache(cacheKey, 'icon');
253  }
254
255  /**
256   * Replace app items in the bundleInfoList.
257   *
258   * @param {string} bundleName
259   * @param {array} abilityInfos
260   */
261  private replaceItem(bundleName: string, abilityInfos): void {
262    Log.showDebug(TAG, `replaceItem bundleName: ${bundleName}`);
263    this.removeItem(bundleName);
264    this.appendItem(abilityInfos);
265  }
266
267  /**
268   * Put shortcut info into map.
269   *
270   * @param {string} bundleName
271   * @param {array} shortcutInfo
272   */
273  setShortcutInfo(bundleName: string, shortcutInfo: ShortcutInfo[]): void {
274    this.mShortcutInfoMap.set(bundleName, shortcutInfo);
275  }
276
277  /**
278   * Get shortcut info from map.
279   *
280   * @param {string} bundleName
281   * @return {array | undefined} shortcutInfo
282   */
283  getShortcutInfo(bundleName: string): ShortcutInfo[] | undefined {
284    return this.mShortcutInfoMap.get(bundleName);
285  }
286
287  /**
288   * Update shortcut info of map.
289   *
290   * @param {string} bundleName
291   * @param {string | undefined} eventType
292   */
293  private updateShortcutInfo(bundleName, eventType?): void {
294    if (eventType && eventType === EventConstants.EVENT_PACKAGE_REMOVED) {
295      this.mShortcutInfoMap.delete(bundleName);
296      return;
297    }
298    launcherAbilityManager.getShortcutInfo(bundleName, this.setShortcutInfo.bind(this));
299  }
300
301  /**
302   * Close popup.
303   */
304  private closePopup(): void {
305    ContextMenu.close();
306  }
307}