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 Ability from '@ohos.app.ability.UIAbility';
17import wantConstant from '@ohos.ability.wantConstant';
18import data_preferences from '@ohos.data.preferences';
19import {
20  AlbumDefine,
21  BigDataConstants,
22  BroadCastConstants,
23  BroadCastManager,
24  Constants,
25  Log,
26  MediaDataSource,
27  MediaObserver,
28  ReportToBigDataUtil,
29  ScreenManager,
30  StatusBarColorController,
31  UserFileManagerAccess
32} from '@ohos/common';
33import { TimelineDataSourceManager } from '@ohos/timeline';
34import router from '@ohos.router';
35import deviceInfo from '@ohos.deviceInfo';
36import type Want from '@ohos.app.ability.Want';
37import type window from '@ohos.window';
38import type AbilityConstant from '@ohos.app.ability.AbilityConstant';
39import common from '@ohos.app.ability.common';
40import { SmartPickerUtils } from '@ohos/thirdselect/src/main/ets/default/utils/SmartPickerUtils';
41
42const TAG: string = 'MainAbility';
43let isFromCard = false;
44let isFromCamera = false;
45let mCallerBundleName: string = '';
46let mMaxSelectCount: number = 0;
47let mFilterMediaType: string = AlbumDefine.FILTER_MEDIA_TYPE_ALL;
48let appBroadCast = BroadCastManager.getInstance().getBroadCast();
49let isShowMenuFromThirdView: boolean;
50let cameraAble: boolean = true;
51let editAble: boolean = true;
52
53export default class MainAbility extends Ability {
54  private formCurrentUri: string = '';
55  private formAlbumUri: string = '';
56  private preselectedUris: Array<string> = [];
57  private isOnDestroy: boolean = false;
58  private localStorage: LocalStorage = new LocalStorage();
59
60  onCreate(want: Want, param: AbilityConstant.LaunchParam): void {
61    AppStorage.setOrCreate('photosAbilityContext', this.context);
62    AppStorage.setOrCreate('formContext', this.context);
63    this.isOnDestroy = false;
64    this.initPhotosPref();
65
66    this.parseWantParameter(false, want);
67
68    UserFileManagerAccess.getInstance().onCreate(AppStorage.get<common.UIAbilityContext>('photosAbilityContext'));
69    MediaObserver.getInstance().registerForAllPhotos();
70    MediaObserver.getInstance().registerForAllAlbums();
71    if (!isFromCard && !isFromCamera) {
72      TimelineDataSourceManager.getInstance();
73    }
74
75    appBroadCast.on(BroadCastConstants.THIRD_ROUTE_PAGE, this.thirdRouterPage.bind(this));
76
77    // Init system album information
78    UserFileManagerAccess.getInstance().prepareSystemAlbums();
79    Log.info(TAG, 'Application onCreate end');
80  }
81
82  onNewWant(want: Want): void {
83    if (this.isOnDestroy) {
84      Log.error(TAG, 'Application is already on isOnDestroy, do nothing in onNewWant');
85      return;
86    }
87    this.parseWantParameter(true, want);
88    this.thirdRouterPage();
89    Log.info(TAG, 'Application onNewWant end');
90  }
91
92  parseWantParameter(isOnNewWant: boolean, want: Want): void {
93    Log.info(TAG, `Application isOnNewWant=${isOnNewWant}, want=${JSON.stringify(want)}`);
94    AppStorage.setOrCreate('placeholderIndex', -1);
95    this.formCurrentUri = '';
96    this.formAlbumUri = '';
97    let wantParam: { [key: string]: Object } = want.parameters;
98    let wantParamUri: string = wantParam?.uri as string;
99    if (wantParamUri === Constants.WANT_PARAM_URI_DETAIL) {
100      isFromCamera = true;
101      if (isOnNewWant) {
102        AppStorage.setOrCreate('entryFromHapCamera', Constants.ENTRY_FROM_CAMERA);
103        AppStorage.get<window.WindowStage>('photosWindowStage').loadContent('pages/PhotoBrowser', (err, data) => {
104          if (err.code) {
105            Log.error(TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
106            return;
107          }
108          Log.info(TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
109        });
110      } else {
111        AppStorage.setOrCreate('entryFromHap', Constants.ENTRY_FROM_CAMERA);
112      }
113    } else if (wantParamUri === Constants.WANT_PARAM_URI_SELECT_SINGLE) {
114      mCallerBundleName = wantParam[Constants.KEY_WANT_PARAMETERS_CALLER_BUNDLE_NAME] as string;
115
116      // Max select count must be 1 in single select mode
117      mMaxSelectCount = Constants.NUMBER_1;
118      mFilterMediaType = wantParam?.filterMediaType as string;
119      AppStorage.setOrCreate('entryFromHap', Constants.ENTRY_FROM_SINGLE_SELECT);
120      cameraAble = (wantParam?.isPhotoTakingSupported as boolean) ?? true;
121      editAble = (wantParam?.isEditSupported as boolean) ?? true;
122      SmartPickerUtils.initIfNeeded(this.context, want, this.localStorage);
123    } else if (wantParamUri === Constants.WANT_PARAM_URI_SELECT_MULTIPLE) {
124      mCallerBundleName = wantParam[Constants.KEY_WANT_PARAMETERS_CALLER_BUNDLE_NAME] as string;
125      mMaxSelectCount = wantParam?.maxSelectCount as number;
126      mFilterMediaType = wantParam?.filterMediaType as string;
127      this.preselectedUris = wantParam?.preselectedUris as Array<string>;
128      AppStorage.setOrCreate('entryFromHap', Constants.ENTRY_FROM_MULTIPLE_SELECT);
129      cameraAble = (wantParam?.isPhotoTakingSupported as boolean) ?? true;
130      editAble = (wantParam?.isEditSupported as boolean) ?? true;
131      SmartPickerUtils.initIfNeeded(this.context, want, this.localStorage);
132    } else if (wantParamUri === Constants.WANT_PARAM_URI_FORM) {
133      isFromCard = true;
134      AppStorage.setOrCreate('entryFromHap', Constants.ENTRY_FROM_FORM_ABILITY);
135      AppStorage.setOrCreate('form_albumUri', wantParam?.albumUri);
136      AppStorage.setOrCreate('form_currentUri', wantParam?.currentUri);
137      AppStorage.setOrCreate('form_currentIndex', wantParam?.currentIndex);
138      AppStorage.setOrCreate('form_displayName', wantParam?.displayName);
139      this.formAlbumUri = wantParam?.albumUri as string;
140      this.formCurrentUri = wantParam?.currentUri as string;
141    } else if (wantParam?.formId) {
142      AppStorage.setOrCreate('FASetting_FormId', wantParam.formId);
143      AppStorage.setOrCreate('entryFromHap', Constants.ENTRY_FROM_FORM_FORM_EDITOR);
144    } else if (want.action === wantConstant.Action.ACTION_VIEW_DATA) {
145      isShowMenuFromThirdView = wantParam.isShowMenu as boolean;
146      AppStorage.setOrCreate('entryFromHap', Constants.ENTRY_FROM_VIEW_DATA);
147      if (want.uri) {
148        AppStorage.setOrCreate('viewDataUri', want.uri);
149      } else {
150        AppStorage.setOrCreate('viewDataUri', wantParamUri);
151      }
152      if (wantParam?.albumUri) {
153        AppStorage.setOrCreate('viewDataAlbumUri', wantParam.albumUri);
154      } else {
155        AppStorage.setOrCreate('viewDataAlbumUri', '');
156      }
157      if (wantParam?.viewIndex) {
158        AppStorage.setOrCreate('viewDataIndex', wantParam.viewIndex);
159      } else {
160        AppStorage.setOrCreate('viewDataIndex', '');
161      }
162    } else if (wantParamUri === Constants.WANT_PARAM_URI_FORM_NONE) {
163      AppStorage.setOrCreate('entryFromHap', Constants.ENTRY_FROM_FORM_DEFAULT_ABILITY);
164    } else {
165      AppStorage.setOrCreate('entryFromHap', Constants.ENTRY_FROM_NONE);
166    }
167  }
168
169  onDestroy(): void | Promise<void> {
170    // Ability is creating, release resources for this ability
171    Log.info(TAG, 'Application onDestroy');
172    this.isOnDestroy = true;
173    let statusBarColorController: StatusBarColorController = StatusBarColorController.getInstance();
174    statusBarColorController.release();
175    AppStorage.delete('entryFromHap');
176    MediaObserver.getInstance().unregisterForAllPhotos();
177    MediaObserver.getInstance().unregisterForAllAlbums();
178    UserFileManagerAccess.getInstance().onDestroy();
179  }
180
181  onWindowStageCreate(windowStage: window.WindowStage): void {
182    // Main window is created, set main page for this ability
183    Log.info(TAG, 'Application onWindowStageCreate');
184    AppStorage.setOrCreate('photosWindowStage', windowStage);
185    AppStorage.setOrCreate('deviceType',
186    deviceInfo.deviceType == 'phone' || deviceInfo.deviceType == 'default' ? Constants.DEFAULT_DEVICE_TYPE : Constants.PAD_DEVICE_TYPE);
187    ScreenManager.getInstance().on(ScreenManager.ON_LEFT_BLANK_CHANGED, data => {
188      Log.info(TAG, `onleftBlankChanged: ${data}`);
189      AppStorage.setOrCreate('leftBlank', data);
190    });
191    ScreenManager.getInstance().on(ScreenManager.ON_SPLIT_MODE_CHANGED, mode => {
192      Log.info(TAG, `onSplitModeChanged: ${JSON.stringify(mode)}`);
193      ReportToBigDataUtil.report(BigDataConstants.SPLIT_SCREEN_ID, null);
194      AppStorage.setOrCreate('isSplitMode', mode);
195    });
196    Log.info(TAG, 'Application onCreate finish');
197    windowStage.getMainWindow().then((win) => {
198      AppStorage.setOrCreate('mainWindow', win);
199      ScreenManager.getInstance().getAvoidArea();
200      ScreenManager.getInstance().initializationSize(win).then(() => {
201        ScreenManager.getInstance().initWindowMode();
202        // @ts-ignore
203        windowStage.setUIContent(this.context, 'pages/index', null);
204      }).catch(() => {
205        Log.error(TAG, `get device screen info failed.`);
206      });
207      windowStage.disableWindowDecor();
208    });
209  }
210
211  onWindowStageDestroy(): void {
212    ScreenManager.getInstance().destroyWindowMode();
213  }
214
215  onForeground(): void {
216  }
217
218  onBackground(): void {
219  }
220
221  async thirdRouterPage() {
222    let entryFrom = AppStorage.Get('entryFromHap');
223    Log.info(TAG, `thirdRouterPage entryFromHap: ${entryFrom}`);
224    if (entryFrom == Constants.ENTRY_FROM_NONE) {
225      return;
226    }
227    if (entryFrom == Constants.ENTRY_FROM_CAMERA) {
228      let options = {
229        url: 'pages/PhotoBrowser',
230        params: {
231          pageFrom: Constants.ENTRY_FROM.CAMERA
232        }
233      };
234      router.replaceUrl(options);
235
236    } else if (entryFrom == Constants.ENTRY_FROM_SINGLE_SELECT) {
237      ReportToBigDataUtil.report(BigDataConstants.SELECT_PICKER_ID, {
238        'selectType': Constants.ENTRY_FROM_SINGLE_SELECT,
239        'filterMediaType': mFilterMediaType,
240        'maxSelectCount': mMaxSelectCount
241      });
242      let options = {
243        url: 'pages/ThirdSelectPhotoGridPage',
244        params: {
245          bundleName: mCallerBundleName,
246          isMultiPick: false,
247          filterMediaType: mFilterMediaType,
248          isFirstEnter: true,
249          maxSelectCount: mMaxSelectCount,
250          uri: '',
251          cameraAble: cameraAble,
252          editAble: editAble
253        }
254      };
255      router.replaceUrl(options);
256    } else if (entryFrom == Constants.ENTRY_FROM_MULTIPLE_SELECT) {
257      ReportToBigDataUtil.report(BigDataConstants.SELECT_PICKER_ID, {
258        'selectType': Constants.ENTRY_FROM_MULTIPLE_SELECT,
259        'filterMediaType': mFilterMediaType,
260        'maxSelectCount': mMaxSelectCount
261      });
262      let options = {
263        url: 'pages/ThirdSelectPhotoGridPage',
264        params: {
265          bundleName: mCallerBundleName,
266          isMultiPick: true,
267          filterMediaType: mFilterMediaType,
268          isFirstEnter: true,
269          maxSelectCount: mMaxSelectCount,
270          preselectedUris: this.preselectedUris,
271          uri: '',
272          cameraAble: cameraAble,
273          editAble: editAble,
274        }
275      };
276      router.replaceUrl(options);
277    } else if (entryFrom == Constants.ENTRY_FROM_FORM_ABILITY) {
278      if (this.formCurrentUri.length > 0 && this.formAlbumUri.length > 0) {
279        let options = {
280          url: 'pages/PhotoBrowser',
281          params: {
282            pageFrom: Constants.ENTRY_FROM.CARD,
283            albumUri: this.formAlbumUri,
284            uri: this.formCurrentUri
285          }
286        };
287        router.replaceUrl(options);
288        let dataSource: MediaDataSource =
289          new MediaDataSource(Constants.DEFAULT_SLIDING_WIN_SIZE);
290        dataSource.setAlbumUri(this.formAlbumUri);
291        dataSource.initialize();
292        AppStorage.setOrCreate(Constants.APP_KEY_PHOTO_BROWSER, dataSource);
293      } else {
294        let dataSource: MediaDataSource =
295          new MediaDataSource(Constants.DEFAULT_SLIDING_WIN_SIZE);
296        dataSource.setAlbumUri(this.formAlbumUri);
297        dataSource.initialize();
298        let times: number = 0;
299        const COUNT_NUM: number = 100;
300        const DELAY_TIME: number = 50;
301        let intervalId = setInterval(() => {
302          if (dataSource.getRawData(0) || times >= COUNT_NUM) {
303            AppStorage.setOrCreate(Constants.APP_KEY_PHOTO_BROWSER, dataSource);
304            let options = {
305              url: 'pages/PhotoBrowser',
306              params: {
307                pageFrom: Constants.ENTRY_FROM.CARD,
308                albumId: AppStorage.get('form_albumUri'),
309                uri: AppStorage.get('form_currentUri'),
310                index: AppStorage.get('form_currentIndex')
311              }
312            };
313            router.replaceUrl(options);
314            clearInterval(intervalId);
315          }
316          times++;
317        }, DELAY_TIME);
318      }
319    } else if (entryFrom == Constants.ENTRY_FROM_FORM_DEFAULT_ABILITY) {
320      let options = {
321        url: 'pages/DefaultPhotoPage'
322      }
323      router.replaceUrl(options);
324    } else if (entryFrom == Constants.ENTRY_FROM_FORM_FORM_EDITOR) {
325      let options = {
326        url: 'pages/FormEditorPage'
327      }
328      router.replaceUrl(options);
329    } else if (entryFrom == Constants.ENTRY_FROM_VIEW_DATA) {
330      let options = {
331        url: 'pages/PhotoBrowser',
332        params: {
333          pageFrom: Constants.ENTRY_FROM.VIEW_DATA,
334          viewData: AppStorage.Get('viewDataUri'),
335          viewDataAlbum: AppStorage.Get('viewDataAlbumUri'),
336          viewDataIndex: AppStorage.Get('viewDataIndex'),
337          isShowMenuFromThirdView: isShowMenuFromThirdView
338        }
339      };
340      router.replaceUrl(options);
341    }
342    AppStorage.setOrCreate('entryFromHap', Constants.ENTRY_FROM_NONE)
343  }
344
345  private initPhotosPref(): void {
346    Log.info(TAG, 'Application initPhotosPref start');
347    data_preferences.getPreferences(AppStorage.get<common.UIAbilityContext>('photosAbilityContext'), Constants.PHOTOS_STORE_KEY)
348      .then((pref: data_preferences.Preferences) => {
349        pref.get(Constants.IS_FIRST_TIME_DELETE, true).then((data: boolean) => {
350          AppStorage.setOrCreate<boolean>(Constants.IS_FIRST_TIME_DELETE, data);
351        }).catch((err) => {
352          Log.error(TAG, `Failed to get whether first time delete, err: ${err}`);
353        });
354        AppStorage.setOrCreate<data_preferences.Preferences>(Constants.PHOTOS_STORE_KEY, pref)
355      })
356      .catch((err) => {
357        Log.error(TAG, 'Failed to get preferences.');
358      });
359  }
360}