1/* 2 * Copyright (C) 2023-2024 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 photoAccessHelper from '@ohos.file.photoAccessHelper'; 17import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; 18import bundleManager from '@ohos.bundle.bundleManager'; 19import dataSharePredicates from '@ohos.data.dataSharePredicates'; 20import abilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry'; 21import fs, { ListFileOptions } from '@ohos.file.fs'; 22import fileuri from "@ohos.file.fileuri"; 23 24const delegator = abilityDelegatorRegistry.getAbilityDelegator(); 25const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(globalThis.abilityContext); 26const photoType = photoAccessHelper.PhotoType; 27const photoKeys = photoAccessHelper.PhotoKeys; 28const albumKeys = photoAccessHelper.AlbumKeys; 29const albumType = photoAccessHelper.AlbumType; 30const albumSubtype = photoAccessHelper.AlbumSubtype; 31const DEFAULT_SLEEP_TIME = 10; 32 33const context = globalThis.abilityContext; 34const pathDir = context.filesDir; 35 36let validImageExt = ['.jpg'] 37let validVideoExt = ['.mp4'] 38let validVideoMpegExt = ['.mpeg'] 39let validImageGifExt = ['.gif'] 40let validImagePngExt = ['.png'] 41 42export async function sleep(times = DEFAULT_SLEEP_TIME) : Promise<void> { 43 await new Promise(res => setTimeout(res, times)); 44}; 45 46export function fetchAllOption() : photoAccessHelper.FetchOptions { 47 const predicates = new dataSharePredicates.DataSharePredicates(); 48 const ops : photoAccessHelper.FetchOptions = { 49 fetchColumns: [], 50 predicates: predicates 51 }; 52 return ops; 53}; 54 55export function fetchOption(testNum, key, value) : photoAccessHelper.FetchOptions { 56 const predicates = new dataSharePredicates.DataSharePredicates(); 57 predicates.equalTo(key, value); 58 const ops : photoAccessHelper.FetchOptions = { 59 fetchColumns: [], 60 predicates: predicates 61 }; 62 console.info(`${testNum} queryOps: ${key} = ${value}`); 63 return ops; 64}; 65 66export function albumFetchOption(testNum, key, value) : photoAccessHelper.FetchOptions { 67 const predicates = new dataSharePredicates.DataSharePredicates(); 68 predicates.equalTo(key, value); 69 const ops : photoAccessHelper.FetchOptions = { 70 fetchColumns: [], 71 predicates: predicates 72 }; 73 console.info(`${testNum} queryOps: ${key} = ${value}`); 74 return ops; 75}; 76 77export function photoFetchOption(testNum, key, value) : photoAccessHelper.FetchOptions { 78 const predicates = new dataSharePredicates.DataSharePredicates(); 79 predicates.equalTo(key, value); 80 const ops : photoAccessHelper.FetchOptions = { 81 fetchColumns: [ 82 photoKeys.URI, 83 photoKeys.PHOTO_TYPE, 84 photoKeys.DISPLAY_NAME, 85 photoKeys.DATE_ADDED, 86 photoKeys.DATE_MODIFIED, 87 photoKeys.DURATION, 88 photoKeys.WIDTH, 89 photoKeys.HEIGHT, 90 photoKeys.DATE_TAKEN, 91 photoKeys.ORIENTATION, 92 photoKeys.FAVORITE, 93 photoKeys.SIZE, 94 photoKeys.TITLE, 95 photoKeys.POSITION, 96 photoKeys.DATE_TRASHED, 97 photoKeys.HIDDEN, 98 photoKeys.CAMERA_SHOT_KEY, 99 photoKeys.USER_COMMENT, 100 photoKeys.DATE_ADDED_MS, 101 photoKeys.DATE_MODIFIED_MS, 102 photoKeys.DYNAMIC_RANGE_TYPE, 103 photoKeys.COVER_POSITION, 104 photoKeys.BURST_KEY, 105 photoKeys.LCD_SIZE, 106 photoKeys.THM_SIZE, 107 photoKeys.DETAIL_TIME, 108 photoKeys.DATE_TAKEN_MS, 109 'all_exif', 110 ], 111 predicates: predicates 112 }; 113 console.info(`${testNum} queryOps: ${key} = ${value}`); 114 return ops; 115}; 116 117export async function getPermission(name = 'ohos.acts.multimedia.photoaccess') : Promise<void> { 118 try { 119 console.info('getPermission start', name); 120 let permissionState = new Map(); 121 const permissions: Array<Permissions> = [ 122 'ohos.permission.MEDIA_LOCATION', 123 'ohos.permission.READ_IMAGEVIDEO', 124 'ohos.permission.WRITE_IMAGEVIDEO', 125 ]; 126 127 const atManager = abilityAccessCtrl.createAtManager(); 128 const appFlags = bundleManager.ApplicationFlag.GET_APPLICATION_INFO_DEFAULT; 129 const userId = 100; 130 const appInfo = await bundleManager.getApplicationInfo(name, appFlags, userId); 131 const tokenID = appInfo.accessTokenId; 132 for (const permission of permissions) { 133 console.info('getPermission permission: ' + permission); 134 try { 135 await atManager.grantUserGrantedPermission(tokenID, permission, 1); 136 } catch (error) { 137 console.error(`getPermission ${permission} failed`); 138 } 139 permissionState.set(permission, await atManager.verifyAccessToken(tokenID, permission)); 140 } 141 permissionState.forEach((value, key, map) => { 142 if (value !== 0) { 143 console.info(`getPermission failed; permission: ${key}, state: ${value}`); 144 } 145 }); 146 console.info('getPermission end'); 147 } catch (error) { 148 console.error(`getPermission failed, error: ${error}`); 149 } 150}; 151 152export function isNum(value) : boolean { 153 return typeof value === 'number' && !isNaN(value); 154}; 155 156export function getAssetId(uri) : string { 157 const tag = 'Photo/'; 158 const index = uri.indexOf(tag); 159 let str = uri.substring(index + tag.length); 160 console.info(`getAssetId str: ${str}`); 161 return str; 162} 163 164export function getAlbumId(uri) : string { 165 const index = uri.lastIndexOf('/'); 166 let str = uri.substring(index + 1); 167 console.info(`getAlbumId str: ${str}`); 168 return str; 169} 170 171export function genRadomStr(len: number) : string { 172 const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 173 let randomStr = ''; 174 for (let i = 0; i < len; i++) { 175 randomStr += chars.charAt(Math.floor(Math.random() * chars.length)); 176 } 177 return randomStr; 178} 179 180export async function createUserAlbum(testNum, albumName) : Promise<photoAccessHelper.Album> { 181 console.info(`${testNum} createUserAlbum albumName: ${albumName}`); 182 let album: photoAccessHelper.Album; 183 try { 184 const helper = photoAccessHelper.getPhotoAccessHelper(globalThis.abilityContext); 185 album = await helper.createAlbum(albumName); 186 console.info(`${testNum} createUserAlbum suc`); 187 } catch (error) { 188 console.error(`Failed to createUserAlbum! error: ${error}`); 189 throw error; 190 } 191 192 return new Promise((resolve, reject) => { 193 resolve(album); 194 }); 195} 196 197export async function getFileAsset(testNum, fetchOps) : Promise<photoAccessHelper.PhotoAsset> { 198 let asset: photoAccessHelper.PhotoAsset; 199 try { 200 const helper = photoAccessHelper.getPhotoAccessHelper(globalThis.abilityContext); 201 let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset>; 202 fetchResult = await helper.getAssets(fetchOps); 203 console.info(`${testNum} getFileAsset fetchResult: ${fetchResult.getCount()}`); 204 asset = await fetchResult.getFirstObject(); 205 fetchResult.close(); 206 } catch (error) { 207 console.error(`${testNum} getFileAsset error: ${error}`); 208 throw error; 209 } 210 211 return new Promise((resolve, reject) => { 212 resolve(asset); 213 }); 214} 215 216export function getFileAssetFetchResult() : photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> { 217 let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset>; 218 return fetchResult; 219} 220 221export function getAlbumFetchResult() : photoAccessHelper.FetchResult<photoAccessHelper.Album> { 222 let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.Album>; 223 return fetchResult; 224} 225 226export function checkUserAlbum(expect, testNum, album, expectedName, expectedCover) : void { 227 console.info(`${testNum} checkUserAlbum album.albumName: ${album.albumName}, expectedName: ${expectedName}`); 228 expect(album.albumType).assertEqual(albumType.USER); 229 expect(album.albumSubtype).assertEqual(albumSubtype.USER_GENERIC); 230 expect(album.albumName).assertEqual(expectedName); 231 if (expectedCover === '') { 232 expect(album.coverUri).assertEqual(''); 233 } else { 234 expect(album.coverUri).assertEqual(expectedCover); 235 } 236 expect(album.albumUri !== '').assertEqual(true); 237 expect(album.count).assertEqual(0); 238} 239 240export function checkSystemAlbum(expect, testNum, album, expectedSubType) : void { 241 try { 242 console.info(`${testNum} checkSystemAlbum expectedSubType: ${expectedSubType}`); 243 expect(album.albumType).assertEqual(albumType.SYSTEM); 244 expect(album.albumSubtype).assertEqual(expectedSubType); 245 expect(album.albumName).assertEqual(''); 246 expect(album.albumUri !== '').assertEqual(true); 247 } catch (error) { 248 console.error(`Failed to delete all user albums! error: ${error}`); 249 throw error; 250 } 251} 252 253export async function startAbility(bundleName: string, abilityName: string) : Promise<void> { 254 await delegator.executeShellCommand(`aa start -b ${bundleName} -a ${abilityName}`).then(result => { 255 console.info(`[picker] start abilityFinished: ${result}`); 256 }).catch(err => { 257 console.error(`[picker] start abilityFailed: ${err}`); 258 }); 259} 260 261export async function stopAbility(bundleName: string) : Promise<void> { 262 await delegator.executeShellCommand(`aa force-stop ${bundleName}`).then(result => { 263 console.info(`[picker] stop abilityFinished: ${result}`); 264 }).catch(err => { 265 console.error(`[picker] stop abilityFailed: ${err}`); 266 }); 267} 268 269export async function getFileNameArray() { 270 try{ 271 let listFileOption: ListFileOptions = { 272 recursion: true, 273 listNum: 0, 274 filter: { 275 suffix: [], 276 } 277 } 278 listFileOption.filter.suffix = validImageExt.concat(validVideoExt); 279 let nameArray = await fs.listFile(pathDir, listFileOption) 280 return nameArray; 281 } catch (err) { 282 console.error('getFileNameArray failed: ' + err); 283 } 284} 285 286export async function getAllFileNameArray() { 287 try{ 288 let listFileOption: ListFileOptions = { 289 recursion: true, 290 listNum: 0, 291 filter: { 292 suffix: [], 293 } 294 } 295 listFileOption.filter.suffix = validImageExt.concat(validVideoExt).concat(validVideoMpegExt).concat(validImageGifExt).concat(validImagePngExt); 296 let nameArray = await fs.listFile(pathDir, listFileOption) 297 return nameArray; 298 } catch (err) { 299 console.error('getFileNameArray failed: ' + err); 300 } 301} 302 303export async function pushCreateAsset(names: Array<string>){ 304 console.info('pushCreateAsset start') 305 let successNum = 0; 306 try{ 307 console.info('pushCreateAsset name: ' + names) 308 let photoType: photoAccessHelper.PhotoType; 309 let resourceType: photoAccessHelper.ResourceType; 310 let fileNames: string[] = await getFileNameArray(); 311 console.info('pushCreateAsset rawFiles number: ' + fileNames.length); 312 for(let i = 0; i < fileNames.length; i++) { 313 let fileName = fileNames[i]; 314 let filePath = pathDir + '/' + fileName; 315 let fileUri = fileuri.getUriFromPath(filePath); 316 let rawExtension: string = fileName.split('.')[1]; 317 for (let j = 0; j < names.length; j++) { 318 let name = names[j]; 319 if (fileName.includes('error')) continue 320 let extension: string = name.split('.')[1]; 321 if (rawExtension === extension) { 322 let options: photoAccessHelper.CreateOptions = { 323 title: name.split('.')[0] 324 } 325 if (validImageExt.includes(('.' + extension))) { 326 photoType = photoAccessHelper.PhotoType.IMAGE; 327 resourceType = photoAccessHelper.ResourceType.IMAGE_RESOURCE; 328 } else { 329 photoType = photoAccessHelper.PhotoType.VIDEO; 330 resourceType = photoAccessHelper.ResourceType.VIDEO_RESOURCE; 331 } 332 let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest = photoAccessHelper.MediaAssetChangeRequest.createAssetRequest(globalThis.abilityContext, photoType, extension, options); 333 assetChangeRequest.addResource(resourceType, fileUri); 334 await phAccessHelper.applyChanges(assetChangeRequest); 335 console.info(`pushCreateAsset ${name} create success`) 336 successNum++; 337 } 338 } 339 } 340 console.info('Push_createAsset successfully fileNumber: ' + successNum); 341 }catch(err){ 342 console.error('Push_createAsset push resource failed: ' + err) 343 return; 344 } 345} 346 347export async function pushCreateAssetSingle(names: Array<string>){ 348 console.info('pushCreateAssetSingle start') 349 let successNum = 0; 350 try{ 351 console.info('pushCreateAssetSingle name: ' + names) 352 let photoType: photoAccessHelper.PhotoType; 353 let resourceType: photoAccessHelper.ResourceType; 354 let fileNames: string[] = await getAllFileNameArray(); 355 for (let i = 0; i < fileNames.length; i++) { 356 let fileName = fileNames[i]; 357 let filePath = pathDir + '/' + fileName; 358 let fileUri = fileuri.getUriFromPath(filePath); 359 let rawExtension: string = fileName.split('.')[1]; 360 for (let j = 0; j < names.length; j++) { 361 let name = names[j]; 362 if(fileName == '/01.jpg' || fileName == '/01.mp4') continue 363 let extension: string = name.split('.')[1]; 364 if (rawExtension === extension) { 365 let options: photoAccessHelper.CreateOptions = { 366 title: name.split('.')[0] 367 } 368 if (validImageExt.concat(validImageGifExt).concat(validImagePngExt).includes(('.' + extension))) { 369 photoType = photoAccessHelper.PhotoType.IMAGE; 370 resourceType = photoAccessHelper.ResourceType.IMAGE_RESOURCE; 371 } else { 372 photoType = photoAccessHelper.PhotoType.VIDEO; 373 resourceType = photoAccessHelper.ResourceType.VIDEO_RESOURCE; 374 } 375 let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest = photoAccessHelper.MediaAssetChangeRequest.createAssetRequest(globalThis.abilityContext, photoType, extension, options); 376 assetChangeRequest.addResource(resourceType, fileUri); 377 await phAccessHelper.applyChanges(assetChangeRequest); 378 console.info(`pushCreateAssetSingle ${name} create success`) 379 successNum++; 380 } 381 } 382 } 383 console.info('Push_createAsset successfully fileNumber: ' + successNum); 384 }catch(err){ 385 console.error('Push_createAsset push resource failed: ' + err) 386 return; 387 } 388} 389 390export function createSandboxFileUri(extension) { 391 let pathDir = globalThis.abilityContext.filesDir; 392 let path = pathDir + '/test' + new Date().getTime() + '.' + extension; 393 fs.openSync(path, fs.OpenMode.CREATE) 394 return fileuri.getUriFromPath(path); 395} 396 397export async function getBurstKey(testNum: string, fetchOps: photoAccessHelper.FetchOptions): Promise<string | number> { 398 let burstKey: string | number | undefined = -1; 399 try { 400 let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> = await phAccessHelper.getAssets(fetchOps); 401 if (fetchResult === undefined) { 402 console.error(`${testNum} :: getBurstKey :: fetchResult is undefined !`); 403 return burstKey; 404 } 405 let photoAsset: photoAccessHelper.PhotoAsset = await fetchResult.getFirstObject(); 406 if (photoAsset === undefined) { 407 console.error(`${testNum} :: getBurstKey :: photoAsset is undefined !`); 408 return burstKey; 409 } 410 burstKey = photoAsset.get(photoKeys.BURST_KEY).toString(); 411 console.log(`${testNum} :: get burstKey success, burstKey is ${burstKey}`); 412 return burstKey; 413 } catch (error) { 414 console.error(`${testNum} :: getBurstKey failed, msg is ${error}`); 415 return burstKey; 416 } 417} 418 419export async function createMovingPhoto(testNum: string, context: Context, titleName: string) { 420 let photoAsset: photoAccessHelper.PhotoAsset | undefined = undefined; 421 try { 422 let photoType: photoAccessHelper.PhotoType = photoAccessHelper.PhotoType.IMAGE; 423 let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); 424 let extension: string = 'jpg'; 425 let options: photoAccessHelper.CreateOptions = { 426 title: titleName, 427 subtype: photoAccessHelper.PhotoSubtype.MOVING_PHOTO 428 } 429 let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest = 430 photoAccessHelper.MediaAssetChangeRequest.createAssetRequest(context, photoType, extension, options); 431 console.log(`${testNum} :: create assetChangeRequest success`); 432 let photoUri = "file://ohos.acts.multimedia.photoaccess/data/storage/el2/base/haps/phone/photos/test_mov_1.jpg"; 433 let videoUri = "file://ohos.acts.multimedia.photoaccess/data/storage/el2/base/haps/phone/photos/test_mov_1.mp4"; 434 assetChangeRequest.addResource(photoAccessHelper.ResourceType.IMAGE_RESOURCE, photoUri); 435 assetChangeRequest.addResource(photoAccessHelper.ResourceType.VIDEO_RESOURCE, videoUri); 436 console.log(`${testNum} :: add resource success`); 437 await phAccessHelper.applyChanges(assetChangeRequest); 438 console.log(`${testNum} :: applyChange success`); 439 photoAsset = assetChangeRequest.getAsset(); 440 } catch (error) { 441 console.error(`${testNum} :: create moving photo failed, error is ${error}`); 442 } 443 return photoAsset; 444} 445 446export { 447 photoType, 448 photoKeys, 449 albumKeys, 450 albumType, 451 albumSubtype, 452};