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