• 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    Log.info(TAG, `prepareSystemAlbums before :${UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST.length}, \
631     after :${UserFileManagerAccess.SYSTEM_AFTER_USER_ALBUM_LIST.length}`);
632    if (!this.media) {
633      Log.error(TAG, 'prepareSystemAlbums media resource is null!');
634      return;
635    }
636    try {
637      for (let i = 0; i < UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST.length; i++) {
638        let albumSubType = UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST[i];
639        let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, albumSubType);
640        let systemAlbum = await fetchResult.getFirstObject();
641        this.systemAlbumUriMap.set(albumSubType, systemAlbum.albumUri);
642        Log.info(TAG, `prepareSystemAlbums before :${systemAlbum.albumUri}, ${albumSubType}`);
643        fetchResult.close();
644      }
645      for (let i = 0; i < UserFileManagerAccess.SYSTEM_AFTER_USER_ALBUM_LIST.length; i++) {
646        let albumSubType = UserFileManagerAccess.SYSTEM_AFTER_USER_ALBUM_LIST[i];
647        let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, albumSubType);
648        let systemAlbum = await fetchResult.getFirstObject();
649        this.systemAlbumUriMap.set(albumSubType, systemAlbum.albumUri);
650        Log.info(TAG, `prepareSystemAlbums after :${systemAlbum.albumUri}, ${albumSubType}`);
651        fetchResult.close();
652      }
653      return;
654    } catch (err) {
655      Log.error(TAG, `prepareSystemAlbums Get System Album exception! msg:  ${err}`);
656      return;
657    }
658  }
659
660  async getSystemAlbums(): Promise<Array<Album>> {
661    if (!this.media) {
662      Log.error(TAG, 'getSystemAlbums media resource is null!');
663      return undefined;
664    }
665    try {
666      let systemAlbumList: Array<Album> = [];
667      for (let i = 0; i < UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST.length; i++) {
668        let albumSubType = UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST[i];
669        let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, albumSubType);
670        let systemAlbum = await fetchResult.getFirstObject();
671        this.systemAlbumUriMap.set(albumSubType, systemAlbum.albumUri);
672        systemAlbumList.push(systemAlbum);
673        Log.info(TAG, `getSystemAlbums :${systemAlbum.albumUri}`);
674        fetchResult.close();
675      }
676      return systemAlbumList;
677    } catch (err) {
678      Log.error(TAG, `getSystemAlbums Get System Album exception! msg:  ${err}`);
679      return undefined;
680    }
681  }
682
683  async getTrashAlbum(): Promise<Album> {
684    if (!this.media) {
685      Log.error(TAG, 'getTrashAlbum media resource is null!');
686      return undefined;
687    }
688    try {
689      let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.TRASH);
690      let trashAlbum: Album = await fetchResult.getFirstObject();
691      this.systemAlbumUriMap.set(UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE, trashAlbum.albumUri);
692      Log.info(TAG, `getTrashAlbum : ${trashAlbum.albumUri}`);
693      fetchResult.close();
694      return trashAlbum;
695    } catch (err) {
696      Log.error(TAG, `getTrashAlbum Get Trash Album exception! msg:  ${err}`);
697      return undefined;
698    }
699  }
700
701  async getHiddenAlbum(): Promise<Album> {
702    if (!this.media) {
703      Log.error(TAG, 'getHiddenAlbum media resource is null!');
704      return undefined;
705    }
706    try {
707      let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.HIDDEN);
708      let hiddenAlbum: Album = await fetchResult.getFirstObject();
709      Log.info(TAG, `getHiddenAlbum : ${hiddenAlbum.albumUri}`);
710      fetchResult.close();
711      return hiddenAlbum;
712    } catch (err) {
713      Log.error(TAG, `getHiddenAlbum Get Hidden Album exception! msg:  ${err}`);
714      return undefined;
715    }
716  }
717
718  async addFileToAlbum(albumUri: string, sourceAsset: FileAsset) {
719    if (!this.media) {
720      Log.error(TAG, '[getHiddenAlbum] media resource is null!');
721      return undefined;
722    }
723    Log.debug(TAG, `addFileToAlbum albumUri is ` + albumUri + ` sourceAsset is ` + sourceAsset);
724    let album = await this.getAlbumByUri(albumUri);
725    await album.addPhotoAssets([sourceAsset]); // TODO 媒体库支持批量添加,传参后续整改
726  }
727
728  isImage(fileAsset: FileAsset): boolean {
729    return fileAsset.fileType === userFileManager.FileType.IMAGE;
730  }
731
732  isSystemAlbum(album: Album): boolean {
733    return album.albumType === userFileManager.AlbumType.SYSTEM;
734  }
735
736  isTrashAlbum(album: Album): boolean {
737    return album.albumSubType === userFileManager.AlbumSubType.TRASH;
738  }
739
740  isScreenShotAlbum(album: Album): boolean {
741    return album.albumSubType === userFileManager.AlbumSubType.SCREENSHOT;
742  }
743
744  isPhotoAlbum(album: Album): boolean {
745    return album.albumSubType === UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE;
746  }
747
748  isVideoAlbum(album: Album): boolean {
749    return album.albumSubType === userFileManager.AlbumSubType.VIDEO;
750  }
751
752  isFavorAlbum(album: Album): boolean {
753    return album.albumSubType === userFileManager.AlbumSubType.FAVORITE;
754  }
755
756  async getAlbumName(album: Album): Promise<string> {
757    if (this.isSystemAlbum(album)) {
758      // 系统相册,图库自己命名
759      switch (album.albumSubType) {
760        case UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE:
761          return await UiUtil.getResourceString($r('app.string.album_photos'));
762        case UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE:
763          return await UiUtil.getResourceString($r('app.string.album_favor'));
764        case UserFileManagerAccess.VIDEO_ALBUM_SUB_TYPE:
765          return await UiUtil.getResourceString($r('app.string.album_video'));
766        case UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE:
767          return await UiUtil.getResourceString($r('app.string.album_recycle'));
768        case UserFileManagerAccess.SCREENSHOT_ALBUM_SUB_TYPE:
769          return await UiUtil.getResourceString($r('app.string.album_screen_shot'));
770        default:
771          return '';
772      }
773    }
774    // 用户相册,直接返回
775    return album.albumName;
776  }
777
778  getAlbumDateModified(album: Album): number {
779    return album.dateModified;
780  }
781
782  /**
783   * 根据Uri获取相册,不区分系统相册和用户相册
784   * @param albumUri 相册Uri
785   * @returns 目标相册
786   */
787  async getAlbumByUri(albumUri: string): Promise<Album> {
788    Log.debug(TAG, 'getAlbumByUri albumUri is ' + albumUri);
789    if (!this.media) {
790      Log.error(TAG, 'getAlbumByUri media resource is null!');
791      return undefined;
792    }
793    try {
794      let albumFetchOpt = AlbumDefine.getAlbumFetchOptByUri(albumUri);
795      // @ts-ignore // TODO 支持不传入type时删掉 ts-ignore
796      let fetchResult: userFileManager.FetchResult<Album> = await this.media.getAlbums(albumFetchOpt);
797      if (!fetchResult) {
798        Log.warn(TAG, 'getAlbumByUri return null');
799        return undefined;
800      }
801      Log.debug(TAG, `getAlbumByUri return raw data size: ${fetchResult.getCount()}`);
802      if (fetchResult.getCount() <= 0) {
803        fetchResult.close();
804        return undefined;
805      }
806      let album = await fetchResult.getFirstObject();
807      if (!album) {
808        Log.warn(TAG, `getAlbumByUri result is null`);
809      }
810      fetchResult.close();
811      return album;
812    } catch (err) {
813      Log.error(TAG, `getAlbumByUri Get Album by uri exception! msg:  ${err}`);
814      return undefined;
815    }
816  }
817
818  async getAlbumByName(albumName: string): Promise<Album> {
819    if (!this.media) {
820      Log.error(TAG, 'getAlbumByName media resource is null!');
821      return undefined;
822    }
823    try {
824      Log.info(TAG, `getAlbumByName name: ${albumName}`);
825      let albumFetchOpt = AlbumDefine.getAlbumFetchOptByName(albumName);
826      // @ts-ignore  // TODO 需要媒体库新开接口,支持仅传入fetchOpt
827      let fetchResult: userFileManager.FetchResult<Album> = await this.media.getAlbums(albumFetchOpt);
828      if (!fetchResult) {
829        Log.error(TAG, 'getAlbumByName fetchResult undefined')
830        return undefined;
831      }
832      if (fetchResult.getCount() <= 0) {
833        fetchResult.close();
834        return undefined;
835      }
836      let album = await fetchResult.getFirstObject();
837      if (!album) {
838        Log.error(TAG, 'getAlbumByName album undefined')
839        return undefined;
840      }
841      Log.info(TAG, `getAlbumByName get album success ${JSON.stringify(album)}`)
842      fetchResult.close();
843      return album;
844    } catch (err) {
845      Log.error(TAG, `getAlbumByName exception! msg:  ${err}`);
846      return undefined;
847    }
848  }
849
850  getSystemAlbumUri(subType: userFileManager.AlbumSubType): string {
851    Log.debug(TAG, `getSystemAlbumUri subType: ${subType}`);
852    let uri = this.systemAlbumUriMap.get(subType);
853    Log.debug(TAG, `getSystemAlbumUri uri: ${uri}`);
854    return uri;
855  }
856
857  async createUserAlbum(albumName: string): Promise<Album> {
858    let album: Album = undefined;
859    try {
860      album = await this.media.createAlbum(albumName);
861    } catch (error) {
862      Log.error(TAG, `deleteAlbumByUri error: ${error}`);
863    }
864    return album;
865  }
866
867  async renameAlbum(album: Album, name: string): Promise<void> {
868    if (!this.media) {
869      Log.error(TAG, '[renameAlbum] media resource is null!');
870      return;
871    }
872    try {
873      album.albumName = name;
874      album.commitModify();
875    } catch (err) {
876      Log.error(TAG, `Rename Album exception! msg:  ${err}`);
877      return;
878    }
879  }
880
881  // 判断当前图库是否有相同名字的系统相册,跟随多语言变化
882  async isAlbumNameExistInSystemAlbums(name: string): Promise<boolean> {
883    for (let i = 0; i < UserFileManagerAccess.ALL_SYSTEM_ALBUM_LIST.length; i++) {
884      let systemAlbumName: string;
885      switch (UserFileManagerAccess.ALL_SYSTEM_ALBUM_LIST[i]) {
886        case UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE:
887          systemAlbumName = await UiUtil.getResourceString($r('app.string.album_photos'));
888          break;
889        case UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE:
890          systemAlbumName = await UiUtil.getResourceString($r('app.string.album_favor'));
891          break;
892        case UserFileManagerAccess.VIDEO_ALBUM_SUB_TYPE:
893          systemAlbumName = await UiUtil.getResourceString($r('app.string.album_video'));
894          break;
895        case UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE:
896          systemAlbumName = await UiUtil.getResourceString($r('app.string.album_recycle'));
897          break;
898        case UserFileManagerAccess.SCREENSHOT_ALBUM_SUB_TYPE:
899          systemAlbumName = await UiUtil.getResourceString($r('app.string.album_screen_shot'));
900          break;
901        default:
902          break;
903      }
904      if (systemAlbumName === name) {
905        return true;
906      }
907    }
908    return false;
909  }
910}
911
912/**
913 * 文件fetchOption
914 */
915export class FileFetchOptionBuilder {
916  private fetchOption: userFileManager.FetchOptions = {
917    predicates: new dataSharePredicates.DataSharePredicates(),
918    fetchColumns: []
919  };
920
921  constructor(fetchOpt?) {
922    if (fetchOpt) {
923      this.fetchOption = fetchOpt;
924    }
925    this.fetchOption.fetchColumns = Array.prototype.slice.call(UserFileManagerAccess.ALL_IMAGE_VIDEO_FETCH_COLUMNS) // 暂时获取所有columns
926  }
927
928  build(): FetchOptions {
929    return this.fetchOption;
930  }
931
932  // 用于timeline分组查询
933  groupBy(): FileFetchOptionBuilder {
934    this.fetchOption.fetchColumns.push(UserFileManagerAccess.GROUP_BY_KEY);
935    return this;
936  }
937
938  media(mediaType: string): FileFetchOptionBuilder {
939    this.fetchOption.predicates.equalTo(userFileManager.ImageVideoKey.FILE_TYPE.toString(), mediaType)
940    return this;
941  }
942
943  uri(uri: string): FileFetchOptionBuilder {
944    this.fetchOption.predicates.equalTo(userFileManager.ImageVideoKey.URI.toString(), uri)
945    return this;
946  }
947
948  order(key: string, isAsc = true): FileFetchOptionBuilder {
949    if (isAsc) {
950      //升序
951      this.fetchOption.predicates.orderByAsc(key);
952    } else {
953      //降序
954      this.fetchOption.predicates.orderByDesc(key);
955    }
956    return this;
957  }
958
959  logicalAnd(): FileFetchOptionBuilder {
960    this.fetchOption.predicates.and();
961    return this;
962  }
963
964  select(start: number, count: number): FileFetchOptionBuilder {
965    this.fetchOption.predicates.limit(count, start);
966    return this;
967  }
968
969  displayName(name: string): FileFetchOptionBuilder {
970    this.fetchOption.predicates.equalTo(userFileManager.ImageVideoKey.DISPLAY_NAME.toString(), name);
971    return this;
972  }
973
974  fetchColumns(columns: Array<string>): FileFetchOptionBuilder {
975    this.fetchOption.fetchColumns = columns;
976    return this;
977  }
978}
979
980/**
981 * 相册fetchOption
982 */
983export class AlbumFetchOptionBuilder {
984  private fetchOption: userFileManager.FetchOptions = {
985    predicates: new dataSharePredicates.DataSharePredicates(),
986    fetchColumns: []
987  };
988
989  constructor(fetchOpt?) {
990    if (fetchOpt) {
991      this.fetchOption = fetchOpt;
992    }
993  }
994
995  build(): FetchOptions {
996    return this.fetchOption;
997  }
998
999  media(mediaType: string): AlbumFetchOptionBuilder {
1000    this.fetchOption.predicates.equalTo(userFileManager.AlbumKey.FILE_TYPE.toString(), mediaType)
1001    return this;
1002  }
1003
1004  logicalAnd(): AlbumFetchOptionBuilder {
1005    this.fetchOption.predicates.and();
1006    return this;
1007  }
1008
1009  albumName(name: string): AlbumFetchOptionBuilder {
1010    this.fetchOption.predicates.equalTo(userFileManager.AlbumKey.ALBUM_NAME.toString(), name);
1011    return this;
1012  }
1013
1014  albumUri(uri: string): AlbumFetchOptionBuilder {
1015    this.fetchOption.predicates.equalTo(userFileManager.AlbumKey.URI.toString(), uri);
1016    return this;
1017  }
1018}