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}