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}