• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 { Log } from '../utils/Log';
17import userFileManager from '@ohos.filemanagement.userFileManager';
18import { Constants } from '../model/common/Constants';
19import { TraceControllerUtils } from '../utils/TraceControllerUtils';
20import dataSharePredicates from '@ohos.data.dataSharePredicates';
21import { UiUtil } from '../utils/UiUtil';
22import { AlbumDefine } from '../model/browser/AlbumDefine';
23
24const TAG: string = 'common_UserFileManagerAccess';
25
26export type UserFileManager = userFileManager.UserFileManager;
27
28export type FileType = userFileManager.FileType;
29
30export type FetchOptions = userFileManager.FetchOptions;
31
32export type FileAsset = userFileManager.FileAsset;
33
34export type MediaPeerInfo = userFileManager.PeerInfo;
35
36export type Album = userFileManager.Album;
37
38export type ImageVideoKey = userFileManager.ImageVideoKey;
39
40export type AlbumKey = userFileManager.AlbumKey;
41
42export type AlbumType = userFileManager.AlbumType;
43
44export type AlbumSubType = userFileManager.AlbumSubType;
45
46export type DefaultChangeUri = userFileManager.DefaultChangeUri;
47
48export type ChangeData = userFileManager.ChangeData;
49
50export type FileAssetEx = {
51  count: number;
52  obj: FileAsset;
53};
54
55export class UserFileManagerAccess {
56  static readonly REGISTER_TYPE_IMAGE_CHANGE = 'imageChange';
57  static readonly REGISTER_TYPE_VIDEO_CHANGE = 'videoChange';
58  static readonly REGISTER_TYPE_DEVICE_CHANGE = 'deviceChange';
59  static readonly REGISTER_TYPE_ALBUM_CHANGE = 'albumChange';
60  static readonly REGISTER_TYPE_REMOTE_FILE_CHANGE = 'remoteFileChange';
61  static readonly MEDIA_TYPE_IMAGE = userFileManager.FileType.IMAGE;
62  static readonly MEDIA_TYPE_VIDEO = userFileManager.FileType.VIDEO;
63  static readonly FILE_KEY_MEDIA_TYPE = userFileManager.ImageVideoKey.FILE_TYPE;
64  static readonly FILE_KEY_DISPLAY_NAME = userFileManager.ImageVideoKey.DISPLAY_NAME;
65  static readonly FILE_KEY_DATE_TAKEN = userFileManager.ImageVideoKey.DATE_ADDED;
66  static readonly FILE_KEY_DATE_TRASHED = userFileManager.ImageVideoKey.DATE_TRASHED;
67  static readonly FILE_KEY_TITLE = userFileManager.ImageVideoKey.TITLE;
68
69  static readonly REGISTER_TYPE_ALL_PHOTOS = "file://media/Photo";
70  static readonly REGISTER_TYPE_ALL_ALBUMS = "file://media/PhotoAlbum";
71  static readonly NOTIFY_ADD = userFileManager.NotifyType.NOTIFY_ADD;
72  static readonly NOTIFY_UPDATE = userFileManager.NotifyType.NOTIFY_UPDATE;
73  static readonly NOTIFY_REMOVE = userFileManager.NotifyType.NOTIFY_REMOVE;
74  static readonly NOTIFY_ALBUM_ADD_ASSET = userFileManager.NotifyType.NOTIFY_ALBUM_ADD_ASSET;
75  static readonly NOTIFY_ALBUM_REMOVE_ASSET = userFileManager.NotifyType.NOTIFY_ALBUM_REMOVE_ASSET;
76
77  static readonly ALL_IMAGE_VIDEO_FETCH_COLUMNS: Array<string> = [
78    userFileManager.ImageVideoKey.URI.toString(),
79    userFileManager.ImageVideoKey.FILE_TYPE.toString(),
80    userFileManager.ImageVideoKey.DISPLAY_NAME.toString(),
81    userFileManager.ImageVideoKey.DATE_ADDED.toString(),
82    userFileManager.ImageVideoKey.DATE_MODIFIED.toString(),
83    userFileManager.ImageVideoKey.TITLE.toString(),
84    userFileManager.ImageVideoKey.DURATION.toString(),
85    userFileManager.ImageVideoKey.WIDTH.toString(),
86    userFileManager.ImageVideoKey.HEIGHT.toString(),
87    userFileManager.ImageVideoKey.DATE_TAKEN.toString(),
88    userFileManager.ImageVideoKey.ORIENTATION.toString(),
89    userFileManager.ImageVideoKey.FAVORITE.toString(),
90    userFileManager.ImageVideoKey.POSITION.toString(),
91    userFileManager.ImageVideoKey.DATE_TRASHED.toString(),
92    userFileManager.ImageVideoKey.HIDDEN.toString(),
93    "size" // TODO 等媒体库枚举字段上库
94  ]
95
96  static readonly GROUP_BY_KEY: string = 'count(*)';
97
98  static readonly IMAGE_ALBUM_SUB_TYPE: AlbumSubType = 1031; // TODO 等媒体库枚举字段上库
99  static readonly CAMERA_ALBUM_SUB_TYPE: AlbumSubType = userFileManager.AlbumSubType.CAMERA;
100  static readonly FAVORITE_ALBUM_SUB_TYPE: AlbumSubType = userFileManager.AlbumSubType.FAVORITE;
101  static readonly VIDEO_ALBUM_SUB_TYPE: AlbumSubType = userFileManager.AlbumSubType.VIDEO;
102  static readonly TRASH_ALBUM_SUB_TYPE: AlbumSubType = userFileManager.AlbumSubType.TRASH;
103  static readonly SCREENSHOT_ALBUM_SUB_TYPE: AlbumSubType = userFileManager.AlbumSubType.SCREENSHOT;
104  static readonly HIDDEN_ALBUM_SUB_TYPE: AlbumSubType = userFileManager.AlbumSubType.HIDDEN;
105
106  static readonly ALL_SYSTEM_ALBUM_LIST: Array<AlbumSubType> = [
107  UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE,
108  UserFileManagerAccess.VIDEO_ALBUM_SUB_TYPE,
109  UserFileManagerAccess.SCREENSHOT_ALBUM_SUB_TYPE,
110  UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE,
111  UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE,
112  UserFileManagerAccess.HIDDEN_ALBUM_SUB_TYPE,
113  UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE,
114  ]
115
116  static readonly SYSTEM_BEFORE_USER_ALBUM_LIST: Array<AlbumSubType> = [
117    UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE,
118    UserFileManagerAccess.VIDEO_ALBUM_SUB_TYPE,
119    UserFileManagerAccess.SCREENSHOT_ALBUM_SUB_TYPE,
120    UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE
121  ]
122
123  static readonly SYSTEM_AFTER_USER_ALBUM_LIST: Array<AlbumSubType> = [
124  UserFileManagerAccess.HIDDEN_ALBUM_SUB_TYPE,
125  UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE
126  ]
127
128  private media: userFileManager.UserFileManager = null;
129  private requestTime: number;
130
131  private systemAlbumUriMap: Map<AlbumSubType, string> = new Map<AlbumSubType, string>();
132
133  constructor() {
134    this.requestTime = Date.now();
135  }
136
137  public static getInstance(): UserFileManagerAccess {
138    if (AppStorage.Get(Constants.APP_KEY_INSTANCE_MEDIA_LIBRARY_ACCESS) == null) {
139      AppStorage.SetOrCreate(Constants.APP_KEY_INSTANCE_MEDIA_LIBRARY_ACCESS, new UserFileManagerAccess());
140    }
141    return AppStorage.Get(Constants.APP_KEY_INSTANCE_MEDIA_LIBRARY_ACCESS);
142  }
143
144  onCreate(context) {
145    Log.debug(TAG, `Photos_UserFileManagerAccess onCreate ${context}`);
146    if (this.media) {
147      Log.debug(TAG, `Photos_UserFileManagerAccess onCreate already`);
148      return;
149    }
150    this.media = userFileManager.getUserFileMgr(context);
151    Log.debug(TAG, 'Photos_UserFileManagerAccess onCreate end');
152    if (!this.media) {
153      Log.error(TAG, 'get media library instance failed!');
154    }
155    Log.info(TAG, 'onCreate done');
156  }
157
158  onDestroy() {
159    try {
160      this.media && this.media.release();
161      this.media = null;
162      Log.info(TAG, 'onDestroy done');
163    } catch (err) {
164      Log.error(TAG, `onDestroy error: ${err}`);
165    }
166  }
167
168  getMediaLibrary(): userFileManager.UserFileManager {
169    return this.media;
170  }
171
172  getSystemAlbumUriMap() {
173    return this.systemAlbumUriMap;
174  }
175
176  async getAllObject(fetchOpt: FetchOptions): Promise<Array<FileAsset>> {
177    Log.info(TAG, `getAllObject: ${JSON.stringify(fetchOpt)}`);
178    if (!this.media) {
179      Log.error(TAG, '[getAllObject] media resource is null!');
180      return [];
181    }
182    try {
183      TraceControllerUtils.startTraceWithTaskId('getAllObject', this.requestTime);
184      let dataList = await this.media.getPhotoAssets(fetchOpt);
185      if (!dataList) {
186        Log.warn(TAG, 'get all Object Data with empty dataList');
187        return [];
188      }
189      Log.debug(TAG, `get all Object Data raw data size: ${dataList.getCount()}`);
190      if (dataList.getCount() <= 0) {
191        dataList.close();
192        return [];
193      }
194
195      let result = await dataList.getAllObject();
196      dataList.close();
197      TraceControllerUtils.finishTraceWithTaskId('getAllObject', this.requestTime);
198      return result;
199    } catch (error) {
200      Log.error(TAG, `getAllObject error: ${error}`);
201      return [];
202    }
203  }
204
205  async deleteAlbumByUri(uri: string): Promise<void> {
206    if (!this.media) {
207      Log.error(TAG, '[deleteAlbum] media resource is null!');
208      return;
209    }
210    try {
211      Log.debug(TAG, `deleteAlbumByUri uri is ` + uri);
212      let album = await this.getAlbumByUri(uri);
213      await this.media.deleteAlbums([album]); // TODO 接口支持批量删除,传参后续整改
214    } catch (error) {
215      Log.error(TAG, `deleteAlbumByUri error: ${error}`);
216      return;
217    }
218  }
219
220  async getCount(fetchOpt: FetchOptions): Promise<number> {
221    Log.info(TAG, `getCount: ${JSON.stringify(fetchOpt)}`);
222    if (!this.media) {
223      Log.error(TAG, '[getCount] media resource is null!');
224      return 0;
225    }
226    try {
227      TraceControllerUtils.startTraceWithTaskId('getCount', this.requestTime);
228      let dataList = await this.media.getPhotoAssets(fetchOpt);
229      if (!dataList) {
230        Log.warn(TAG, 'get count dataList is 0');
231        return 0;
232      }
233      Log.debug(TAG, `get count raw data size: ${dataList.getCount()}`);
234      let result = dataList.getCount();
235      dataList.close();
236      TraceControllerUtils.finishTraceWithTaskId('getCount', this.requestTime);
237      return result;
238    } catch (error) {
239      Log.error(TAG, `get Count error:  ${error}`);
240      return 0;
241    }
242  }
243
244  async getObject(fetchOpt: FetchOptions): Promise<FileAsset> {
245    Log.info(TAG, `getObject: ${JSON.stringify(fetchOpt)}`);
246    if (!this.media) {
247      Log.error(TAG, '[getObject] media resource is null!');
248      return undefined;
249    }
250    try {
251      TraceControllerUtils.startTraceWithTaskId('getObject', this.requestTime);
252      let fileResult = await this.media.getPhotoAssets(fetchOpt);
253      if (fileResult) {
254        Log.info(TAG, `getObject count is ${fileResult.getCount()}`);
255        if (fileResult.getCount() <= 0) {
256          fileResult.close();
257          return undefined;
258        }
259        let file = await fileResult.getFirstObject();
260        fileResult.close();
261        if (file) {
262          return file;
263        } else {
264          Log.error(TAG, 'Failed getObject');
265        }
266      }
267      TraceControllerUtils.finishTraceWithTaskId('getObject', this.requestTime);
268      return undefined;
269    } catch (error) {
270      Log.error(TAG, `getObject loadData error: ${error}`);
271      return undefined;
272    }
273  }
274
275  async getFirstObject(fetchOpt: FetchOptions): Promise<FileAssetEx> {
276    let result = {
277      count: 0,
278      obj: null
279    }
280    Log.info(TAG, `getFirstObject: ${JSON.stringify(fetchOpt)}`);
281    if (!this.media) {
282      Log.error(TAG, '[getFirstObject] media resource is null!');
283      return result;
284    }
285    try {
286      TraceControllerUtils.startTraceWithTaskId('getFirstObject', this.requestTime);
287      let fileResult = await this.media.getPhotoAssets(fetchOpt);
288      if (fileResult) {
289        result.count = fileResult.getCount();
290        Log.info(TAG, `getFirstObject count is ${result.count}`);
291        if (result.count <= 0) {
292          fileResult.close();
293          return result;
294        }
295        let file = await fileResult.getFirstObject();
296        fileResult.close();
297        if (file) {
298          result.obj = file;
299          return result;
300        } else {
301          Log.error(TAG, 'Failed getFirstObject');
302        }
303      }
304      TraceControllerUtils.finishTraceWithTaskId('getFirstObject', this.requestTime);
305      return result;
306    } catch (error) {
307      Log.error(TAG, `getFirstObject loadData error: ${error}`);
308      return result;
309    }
310  }
311
312  async deleteAlbumPhotos(uri: String): Promise<void> {
313    Log.debug(TAG, `deleteAsset uri: ${uri}`);
314    if (!this.media) {
315      Log.error(TAG, '[deleteAsset] media resource is null!');
316      return;
317    }
318
319    // 获取回收站内的文件
320    let predicates = new dataSharePredicates.DataSharePredicates();
321    let fetchOptions = {
322      fetchColumns: [],
323      predicates: predicates
324    };
325
326    try {
327      const fetchResult = await this.media.getPhotoAssets(fetchOptions);
328      var asset = await fetchResult.getFirstObject();
329    } catch (err) {
330      console.info('fetch failed, message =', err);
331    }
332
333    if (asset == undefined) {
334      console.error('asset not exist');
335      return;
336    }
337    try {
338      await this.media.delete(asset.uri);
339      console.info("delete successfully");
340    } catch (err) {
341      console.error("delete failed with error: " + err);
342    }
343  }
344
345  async createAsset(mediaType: FileType, displayName: string): Promise<FileAsset> {
346    Log.debug(TAG, 'createAsset start');
347    if (!this.media) {
348      Log.error(TAG, '[createAsset] media resource is null!');
349      return null;
350    }
351    Log.info(TAG, `createAsset ${mediaType} ${displayName} `);
352    let fileAsset = await this.media.createPhotoAsset(displayName);
353    Log.debug(TAG, `createAsset end. new fileAsset: ${fileAsset}`);
354    if (!fileAsset) {
355      Log.error(TAG, 'createAsset Fail');
356      return null;
357    }
358    return fileAsset;
359  }
360
361  async openAsset(mode: string, fileAsset: FileAsset): Promise<number> {
362    Log.debug(TAG, 'openAsset start');
363    if (!fileAsset) {
364      Log.error(TAG, 'fileAsset is null');
365      return;
366    }
367    let fd = await fileAsset.open(mode);
368    Log.info(TAG, `openAsset end. fd: ${fd}`);
369    if (fd <= 0) {
370      Log.error(TAG, 'openAsset Fail');
371      return;
372    }
373    return fd;
374  }
375
376  async closeAsset(fd: number, fileAsset: FileAsset): Promise<void> {
377    Log.debug(TAG, 'closeAsset start');
378    if (!fileAsset) {
379      Log.error(TAG, 'fileAsset is null');
380      return;
381    }
382    try {
383      await fileAsset.close(fd);
384    } catch (err) {
385      Log.error(TAG, 'file asset close error: ' + JSON.stringify(err));
386    }
387  }
388
389  async deleteToTrash(uri: string): Promise<void> {
390    Log.debug(TAG, 'trashAsset start');
391    await this.media.delete(uri);
392  }
393
394  async deleteFromTrash(assets: Array<FileAsset>): Promise<void> {
395    let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.TRASH);
396    let trashAlbum = await fetchResult.getFirstObject();
397    await trashAlbum.deletePhotoAssets(assets);
398    fetchResult.close();
399  }
400
401  async recoverFromTrash(assets: Array<FileAsset>): Promise<void> {
402    let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.TRASH);
403    let trashAlbum = await fetchResult.getFirstObject();
404    await trashAlbum.recoverPhotoAssets(assets);
405    fetchResult.close();
406  }
407
408  async getTrashAssetByUri(assetUri: string): Promise<FileAsset> {
409    Log.info(TAG, "getTrashAssetByUri");
410    let trashAlbumResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.TRASH);
411    let trashAlbum = await trashAlbumResult.getFirstObject();
412    let predicates = new dataSharePredicates.DataSharePredicates();
413    predicates.equalTo(userFileManager.ImageVideoKey.URI.toString(), assetUri);
414    let fetchOption: userFileManager.FetchOptions = {
415      predicates: predicates,
416      fetchColumns: []
417    };
418    fetchOption.fetchColumns = Array.prototype.slice.call(UserFileManagerAccess.ALL_IMAGE_VIDEO_FETCH_COLUMNS);
419    let fetchResult = await trashAlbum.getPhotoAssets(fetchOption);
420    let assets = await fetchResult.getFirstObject();
421    fetchResult.close();
422    trashAlbumResult.close();
423    return assets;
424  }
425
426  async getFavoriteObject(fetchOpt: FetchOptions): Promise<Array<FileAsset>> {
427    if (!this.media) {
428      Log.error(TAG, '[getFavoriteObject] media resource is null!');
429      return [];
430    }
431    try {
432      let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.FAVORITE);
433      let favoriteAlbum = await fetchResult.getFirstObject();
434      let fileFetchResult = await favoriteAlbum.getPhotoAssets(fetchOpt)
435      Log.info(TAG, `[getFavoriteObject] get smart albums length:${fileFetchResult.getCount()} name:${favoriteAlbum.albumName}`);
436      Log.debug(TAG, `[getFavoriteObject] object count :${fileFetchResult.getCount()}`);
437      let objects = await fileFetchResult.getAllObject();
438      Log.debug(TAG, `[getFavoriteObject] objects done`);
439      fileFetchResult.close();
440      fetchResult.close();
441      return objects;
442    } catch (err) {
443      Log.error(TAG, `Get favorite object exception! msg:  ${err}`);
444      return [];
445    }
446  }
447
448  async getTrashObject(fetchOpt: FetchOptions): Promise<Array<FileAsset>> {
449    Log.info(TAG, `Get trash object: ${JSON.stringify(fetchOpt)}`);
450    if (!this.media) {
451      Log.error(TAG, '[getTrashObject] media resource is null!');
452      return [];
453    }
454    try {
455      let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.TRASH);
456      let trashAlbum = await fetchResult.getFirstObject();
457      let fileFetchResult = await trashAlbum.getPhotoAssets(fetchOpt)
458      Log.debug(TAG, `[getTrashObject] object count :${fileFetchResult.getCount()}`);
459      let objects = await fileFetchResult.getAllObject();
460      Log.debug(TAG, `[getTrashObject] get objects done`);
461      fileFetchResult.close();
462      fetchResult.close();
463      return objects;
464    } catch (err) {
465      Log.error(TAG, `Get Trash Object exception! msg: ${err}`);
466      return [];
467    }
468  }
469
470  async getUserAlbumObject(fetchOpt: FetchOptions, fileFetchOpt: FetchOptions): Promise<Array<FileAsset>> {
471    Log.info(TAG, `getEntityAlbumObject opt${JSON.stringify(fetchOpt)} fileOpt${JSON.stringify(fileFetchOpt)}`);
472    if (!this.media) {
473      Log.error(TAG, '[getEntityAlbumObject] media resource is null!');
474      return [];
475    }
476    try {
477      // 按照fetchOpt获取用户指定的相册---游标
478      let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.USER, userFileManager.AlbumSubType.USER_GENERIC, fetchOpt);
479
480      //获取所有的相册的
481      let albums = await fetchResult.getAllObject();
482      if (albums.length === 0) {
483        return [];
484      }
485      let objects = [];
486      for (let i = 0; i < albums.length; i++) {
487        let album = albums[i];
488        Log.debug(TAG, `[getEntityAlbumObject]Albums name:${album.albumName}  index: ${i}`);
489        // 返回一个游标
490        let fileResult = await album.getPhotoAssets(fileFetchOpt);
491        Log.debug(TAG, `[getEntityAlbumObject]objects count :${fileResult.getCount()}`);
492        if (fileResult.getCount() <= 0) {
493          fileResult.close();
494          continue;
495        }
496        //获取该album游标下的所有资源
497        objects = await fileResult.getAllObject();
498        Log.debug(TAG, `[getEntityAlbumObject]Get objects done`);
499        fileResult.close();
500      }
501      fetchResult.close();
502      return objects;
503    } catch (err) {
504      Log.error(TAG, `Get Entity Album Object exception! msg:  ${err}`);
505      return [];
506    }
507  }
508
509  async getFavoriteCount(favoriteFetchOpt: FetchOptions): Promise<number> {
510    Log.info(TAG, `[getFavoriteCount] FetchOptions: ${JSON.stringify(favoriteFetchOpt)}`);
511    return await this.getSystemAlbumCount(favoriteFetchOpt, userFileManager.AlbumSubType.FAVORITE);
512  }
513
514  async getTrashCount(trashFetchOpt: FetchOptions): Promise<number> {
515    Log.info(TAG, `[getTrashCount] FetchOptions: ${JSON.stringify(trashFetchOpt)}`);
516    return await this.getSystemAlbumCount(trashFetchOpt, userFileManager.AlbumSubType.TRASH);
517  }
518
519  async getSystemAlbumCount(fetchOpt: FetchOptions, albumSubType: userFileManager.AlbumSubType): Promise<number> {
520    Log.info(TAG, `[getTrashCount] FetchOptions: ${JSON.stringify(fetchOpt)}`);
521    if (!this.media) {
522      Log.error(TAG, '[getTrashCount] media resource is null!');
523      return 0;
524    }
525    try {
526      let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, albumSubType);
527      let systemAlbum = await fetchResult.getFirstObject();
528      let fileFetchResult = await systemAlbum.getPhotoAssets(fetchOpt)
529      let count = fileFetchResult.getCount();
530      fileFetchResult.close();
531      fetchResult.close();
532      return count;
533    } catch (err) {
534      Log.error(TAG, `Get Trash count exception! msg: ${err}`);
535      return 0;
536    }
537  }
538
539  async getAlbumFirstObject(album: Album): Promise<FileAsset> {
540    Log.info(TAG, `[getAlbumFirstObject]`);
541    if (!this.media) {
542      Log.error(TAG, '[getAlbumFirstObject] media resource is null!');
543      return undefined;
544    }
545    try {
546      let opt = AlbumDefine.getFileFetchOpt(0, 1);
547      let fetchResult = await album.getPhotoAssets(opt);
548      if (!fetchResult) {
549        Log.error(TAG, 'fetchResult is null');
550      }
551      let fileAsset = await fetchResult.getFirstObject();
552      fetchResult.close();
553      Log.info(TAG, `cover uri ${fileAsset.uri}`);
554      return fileAsset;
555    } catch (err) {
556      Log.error(TAG, `Get album first obj exception! msg: ${err}`);
557      return undefined;
558    }
559  }
560
561  async getUserAlbumCount(albumFetchOpt: FetchOptions, fileFetchOpt?: FetchOptions): Promise<number> {
562    Log.info(TAG, `getUSerAlbumCount FetchOptions: ${JSON.stringify(albumFetchOpt)}`);
563    if (!this.media) {
564      Log.error(TAG, '[getTrashCount] media resource is null!');
565      return 0;
566    }
567    try {
568      let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.USER, userFileManager.AlbumSubType.USER_GENERIC, albumFetchOpt);
569      let userAlbum = await fetchResult.getFirstObject();
570      let fileFetchResult = await userAlbum.getPhotoAssets(fileFetchOpt);
571      let count = fileFetchResult.getCount();
572      fileFetchResult.close();
573      fetchResult.close();
574      return count;
575    } catch (err) {
576      Log.error(TAG, `Get Trash count exception! msg: ${err}`);
577      return 0;
578    }
579  }
580
581  async getUserAlbums(fetchOpt?: FetchOptions): Promise<Array<Album>> {
582    Log.info(TAG, `getUserAlbums start}`);
583    if (!this.media) {
584      Log.error(TAG, '[getUserAlbums] media resource is null!');
585      return [];
586    }
587    try {
588      let fetchResult;
589      if (fetchOpt) {
590        fetchResult = await this.media.getAlbums(userFileManager.AlbumType.USER, userFileManager.AlbumSubType.USER_GENERIC, fetchOpt);
591      } else {
592        fetchResult = await this.media.getAlbums(userFileManager.AlbumType.USER, userFileManager.AlbumSubType.USER_GENERIC);
593      }
594      let userAlbums = await fetchResult.getAllObject();
595      Log.info(TAG, `[getUserAlbums]length :${userAlbums.length}`);
596      fetchResult.close();
597      return userAlbums;
598    } catch (err) {
599      Log.error(TAG, `Get User Album exception! msg:  ${err}`);
600      return [];
601    }
602  }
603
604  async prepareSystemAlbums(): Promise<void> {
605    if (!this.media) {
606      Log.error(TAG, 'prepareSystemAlbums media resource is null!');
607      return;
608    }
609    try {
610      for (let i = 0; i < UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST.length; i++) {
611        let albumSubType = UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST[i];
612        let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, albumSubType);
613        let systemAlbum = await fetchResult.getFirstObject();
614        this.systemAlbumUriMap.set(albumSubType, systemAlbum.albumUri);
615        Log.info(TAG, `prepareSystemAlbums before :${systemAlbum.albumUri}, ${albumSubType}`);
616        fetchResult.close();
617      }
618      for (let i = 0; i < UserFileManagerAccess.SYSTEM_AFTER_USER_ALBUM_LIST.length; i++) {
619        let albumSubType = UserFileManagerAccess.SYSTEM_AFTER_USER_ALBUM_LIST[i];
620        let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, albumSubType);
621        let systemAlbum = await fetchResult.getFirstObject();
622        this.systemAlbumUriMap.set(albumSubType, systemAlbum.albumUri);
623        Log.info(TAG, `prepareSystemAlbums after :${systemAlbum.albumUri}, ${albumSubType}`);
624        fetchResult.close();
625      }
626      return;
627    } catch (err) {
628      Log.error(TAG, `prepareSystemAlbums Get System Album exception! msg:  ${err}`);
629      return;
630    }
631  }
632
633  async getSystemAlbums(): Promise<Array<Album>> {
634    if (!this.media) {
635      Log.error(TAG, 'getSystemAlbums media resource is null!');
636      return undefined;
637    }
638    try {
639      let systemAlbumList: Array<Album> = [];
640      for (let i = 0; i < UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST.length; i++) {
641        let albumSubType = UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST[i];
642        let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, albumSubType);
643        let systemAlbum = await fetchResult.getFirstObject();
644        this.systemAlbumUriMap.set(albumSubType, systemAlbum.albumUri);
645        systemAlbumList.push(systemAlbum);
646        Log.info(TAG, `getSystemAlbums :${systemAlbum.albumUri}`);
647        fetchResult.close();
648      }
649      return systemAlbumList;
650    } catch (err) {
651      Log.error(TAG, `getSystemAlbums Get System Album exception! msg:  ${err}`);
652      return undefined;
653    }
654  }
655
656  async getTrashAlbum(): Promise<Album> {
657    if (!this.media) {
658      Log.error(TAG, 'getTrashAlbum media resource is null!');
659      return undefined;
660    }
661    try {
662      let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.TRASH);
663      let trashAlbum: Album = await fetchResult.getFirstObject();
664      this.systemAlbumUriMap.set(UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE, trashAlbum.albumUri);
665      Log.info(TAG, `getTrashAlbum : ${trashAlbum.albumUri}`);
666      fetchResult.close();
667      return trashAlbum;
668    } catch (err) {
669      Log.error(TAG, `getTrashAlbum Get Trash Album exception! msg:  ${err}`);
670      return undefined;
671    }
672  }
673
674  async getHiddenAlbum(): Promise<Album> {
675    if (!this.media) {
676      Log.error(TAG, 'getHiddenAlbum media resource is null!');
677      return undefined;
678    }
679    try {
680      let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.HIDDEN);
681      let hiddenAlbum: Album = await fetchResult.getFirstObject();
682      Log.info(TAG, `getHiddenAlbum : ${hiddenAlbum.albumUri}`);
683      fetchResult.close();
684      return hiddenAlbum;
685    } catch (err) {
686      Log.error(TAG, `getHiddenAlbum Get Hidden Album exception! msg:  ${err}`);
687      return undefined;
688    }
689  }
690
691  async addFileToAlbum(albumUri: string, sourceAsset: FileAsset) {
692    if (!this.media) {
693      Log.error(TAG, '[getHiddenAlbum] media resource is null!');
694      return undefined;
695    }
696    Log.debug(TAG, `addFileToAlbum albumUri is ` + albumUri + ` sourceAsset is ` + sourceAsset);
697    let album = await this.getAlbumByUri(albumUri);
698    await album.addPhotoAssets([sourceAsset]); // TODO 媒体库支持批量添加,传参后续整改
699  }
700
701  isImage(fileAsset: FileAsset): boolean {
702    return fileAsset.fileType === userFileManager.FileType.IMAGE;
703  }
704
705  isSystemAlbum(album: Album): boolean {
706    return album.albumType === userFileManager.AlbumType.SYSTEM;
707  }
708
709  isTrashAlbum(album: Album): boolean {
710    return album.albumSubType === userFileManager.AlbumSubType.TRASH;
711  }
712
713  isScreenShotAlbum(album: Album): boolean {
714    return album.albumSubType === userFileManager.AlbumSubType.SCREENSHOT;
715  }
716
717  isPhotoAlbum(album: Album): boolean {
718    return album.albumSubType === UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE;
719  }
720
721  isVideoAlbum(album: Album): boolean {
722    return album.albumSubType === userFileManager.AlbumSubType.VIDEO;
723  }
724
725  isFavorAlbum(album: Album): boolean {
726    return album.albumSubType === userFileManager.AlbumSubType.FAVORITE;
727  }
728
729  async getAlbumName(album: Album): Promise<string> {
730    if (this.isSystemAlbum(album)) {
731      // 系统相册,图库自己命名
732      switch (album.albumSubType) {
733        case UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE:
734          return await UiUtil.getResourceString($r('app.string.album_photos'));
735        case UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE:
736          return await UiUtil.getResourceString($r('app.string.album_favor'));
737        case UserFileManagerAccess.VIDEO_ALBUM_SUB_TYPE:
738          return await UiUtil.getResourceString($r('app.string.album_video'));
739        case UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE:
740          return await UiUtil.getResourceString($r('app.string.album_recycle'));
741        case UserFileManagerAccess.SCREENSHOT_ALBUM_SUB_TYPE:
742          return await UiUtil.getResourceString($r('app.string.album_screen_shot'));
743        default:
744          return '';
745      }
746    }
747    // 用户相册,直接返回
748    return album.albumName;
749  }
750
751  getAlbumDateModified(album: Album): number {
752    return album.dateModified;
753  }
754
755  /**
756   * 根据Uri获取相册,不区分系统相册和用户相册
757   * @param albumUri 相册Uri
758   * @returns 目标相册
759   */
760  async getAlbumByUri(albumUri: string): Promise<Album> {
761    Log.debug(TAG, 'getAlbumByUri albumUri is ' + albumUri);
762    if (!this.media) {
763      Log.error(TAG, 'getAlbumByUri media resource is null!');
764      return undefined;
765    }
766    try {
767      let albumFetchOpt = AlbumDefine.getAlbumFetchOptByUri(albumUri);
768      // @ts-ignore // TODO 支持不传入type时删掉 ts-ignore
769      let fetchResult = await this.media.getAlbums(albumFetchOpt);
770      if (!fetchResult) {
771        Log.warn(TAG, 'getAlbumByUri return null');
772        return undefined;
773      }
774      Log.debug(TAG, `getAlbumByUri return raw data size: ${fetchResult.getCount()}`);
775      if (fetchResult.getCount() <= 0) {
776        fetchResult.close();
777        return undefined;
778      }
779      let album = await fetchResult.getFirstObject();
780      if (!album) {
781        Log.warn(TAG, `getAlbumByUri result is null`);
782      }
783      fetchResult.close();
784      return album;
785    } catch (err) {
786      Log.error(TAG, `getAlbumByUri Get Album by uri exception! msg:  ${err}`);
787      return undefined;
788    }
789  }
790
791  async getAlbumByName(albumName: string): Promise<Album> {
792    if (!this.media) {
793      Log.error(TAG, 'getAlbumByName media resource is null!');
794      return undefined;
795    }
796    try {
797      Log.info(TAG, `getAlbumByName name: ${albumName}`);
798      let albumFetchOpt = AlbumDefine.getAlbumFetchOptByName(albumName);
799      // @ts-ignore // TODO 需要媒体库新开接口,支持仅传入fetchOpt
800      let fetchResult = await this.media.getAlbums(albumFetchOpt);
801      if (!fetchResult) {
802        Log.error(TAG, 'getAlbumByName fetchResult undefined')
803        return undefined;
804      }
805      if (fetchResult.getCount() <= 0) {
806        fetchResult.close();
807        return undefined;
808      }
809      let album = await fetchResult.getFirstObject();
810      if (!album) {
811        Log.error(TAG, 'getAlbumByName album undefined')
812        return undefined;
813      }
814      Log.info(TAG, `getAlbumByName get album success ${JSON.stringify(album)}`)
815      fetchResult.close();
816      return album;
817    } catch (err) {
818      Log.error(TAG, `getAlbumByName exception! msg:  ${err}`);
819      return undefined;
820    }
821  }
822
823  getSystemAlbumUri(subType: userFileManager.AlbumSubType): string {
824    Log.debug(TAG, `getSystemAlbumUri subType: ${subType}`);
825    let uri = this.systemAlbumUriMap.get(subType);
826    Log.debug(TAG, `getSystemAlbumUri uri: ${uri}`);
827    return uri;
828  }
829
830  async createUserAlbum(albumName: string): Promise<Album> {
831    let album: Album = undefined;
832    try {
833      album = await this.media.createAlbum(albumName);
834    } catch (error) {
835      Log.error(TAG, `deleteAlbumByUri error: ${error}`);
836    }
837    return album;
838  }
839
840  async renameAlbum(album: Album, name: string): Promise<void> {
841    if (!this.media) {
842      Log.error(TAG, '[renameAlbum] media resource is null!');
843      return;
844    }
845    try {
846      album.albumName = name;
847      album.commitModify();
848    } catch (err) {
849      Log.error(TAG, `Rename Album exception! msg:  ${err}`);
850      return;
851    }
852  }
853
854  // 判断当前图库是否有相同名字的系统相册,跟随多语言变化
855  async isAlbumNameExistInSystemAlbums(name: string): Promise<boolean> {
856    for (let i = 0; i < UserFileManagerAccess.ALL_SYSTEM_ALBUM_LIST.length; i++) {
857      let systemAlbumName: string;
858      switch (UserFileManagerAccess.ALL_SYSTEM_ALBUM_LIST[i]) {
859        case UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE:
860          systemAlbumName = await UiUtil.getResourceString($r('app.string.album_photos'));
861          break;
862        case UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE:
863          systemAlbumName = await UiUtil.getResourceString($r('app.string.album_favor'));
864          break;
865        case UserFileManagerAccess.VIDEO_ALBUM_SUB_TYPE:
866          systemAlbumName = await UiUtil.getResourceString($r('app.string.album_video'));
867          break;
868        case UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE:
869          systemAlbumName = await UiUtil.getResourceString($r('app.string.album_recycle'));
870          break;
871        case UserFileManagerAccess.SCREENSHOT_ALBUM_SUB_TYPE:
872          systemAlbumName = await UiUtil.getResourceString($r('app.string.album_screen_shot'));
873          break;
874        default:
875          break;
876      }
877      if (systemAlbumName === name) {
878        return true;
879      }
880    }
881    return false;
882  }
883}
884
885/**
886 * 文件fetchOption
887 */
888export class FileFetchOptionBuilder {
889  private fetchOption: userFileManager.FetchOptions = {
890    predicates: new dataSharePredicates.DataSharePredicates(),
891    fetchColumns: []
892  };
893
894  constructor(fetchOpt?) {
895    if (fetchOpt) {
896      this.fetchOption = fetchOpt;
897    }
898    this.fetchOption.fetchColumns = Array.prototype.slice.call(UserFileManagerAccess.ALL_IMAGE_VIDEO_FETCH_COLUMNS) // 暂时获取所有columns
899  }
900
901  build(): FetchOptions {
902    return this.fetchOption;
903  }
904
905  // 用于timeline分组查询
906  groupBy(): FileFetchOptionBuilder {
907    this.fetchOption.fetchColumns.push(UserFileManagerAccess.GROUP_BY_KEY);
908    return this;
909  }
910
911  media(mediaType: string): FileFetchOptionBuilder {
912    this.fetchOption.predicates.equalTo(userFileManager.ImageVideoKey.FILE_TYPE.toString(), mediaType)
913    return this;
914  }
915
916  uri(uri: string): FileFetchOptionBuilder {
917    this.fetchOption.predicates.equalTo(userFileManager.ImageVideoKey.URI.toString(), uri)
918    return this;
919  }
920
921  order(key: string, isAsc = true): FileFetchOptionBuilder {
922    if (isAsc) {
923      //升序
924      this.fetchOption.predicates.orderByAsc(key);
925    } else {
926      //降序
927      this.fetchOption.predicates.orderByDesc(key);
928    }
929    return this;
930  }
931
932  logicalAnd(): FileFetchOptionBuilder {
933    this.fetchOption.predicates.and();
934    return this;
935  }
936
937  select(start: number, count: number): FileFetchOptionBuilder {
938    this.fetchOption.predicates.limit(count, start);
939    return this;
940  }
941
942  displayName(name: string): FileFetchOptionBuilder {
943    this.fetchOption.predicates.equalTo(userFileManager.ImageVideoKey.DISPLAY_NAME.toString(), name);
944    return this;
945  }
946
947  fetchColumns(columns: Array<string>): FileFetchOptionBuilder {
948    this.fetchOption.fetchColumns = columns;
949    return this;
950  }
951}
952
953/**
954 * 相册fetchOption
955 */
956export class AlbumFetchOptionBuilder {
957  private fetchOption: userFileManager.FetchOptions = {
958    predicates: new dataSharePredicates.DataSharePredicates(),
959    fetchColumns: []
960  };
961
962  constructor(fetchOpt?) {
963    if (fetchOpt) {
964      this.fetchOption = fetchOpt;
965    }
966  }
967
968  build(): FetchOptions {
969    return this.fetchOption;
970  }
971
972  media(mediaType: string): AlbumFetchOptionBuilder {
973    this.fetchOption.predicates.equalTo(userFileManager.AlbumKey.FILE_TYPE.toString(), mediaType)
974    return this;
975  }
976
977  logicalAnd(): AlbumFetchOptionBuilder {
978    this.fetchOption.predicates.and();
979    return this;
980  }
981
982  albumName(name: string): AlbumFetchOptionBuilder {
983    this.fetchOption.predicates.equalTo(userFileManager.AlbumKey.ALBUM_NAME.toString(), name);
984    return this;
985  }
986
987  albumUri(uri: string): AlbumFetchOptionBuilder {
988    this.fetchOption.predicates.equalTo(userFileManager.AlbumKey.URI.toString(), uri);
989    return this;
990  }
991}