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 'all_exif', 108 ], 109 predicates: predicates 110 }; 111 console.info(`${testNum} queryOps: ${key} = ${value}`); 112 return ops; 113}; 114 115export async function getPermission(name = 'ohos.acts.multimedia.photoaccess') : Promise<void> { 116 try { 117 console.info('getPermission start', name); 118 let permissionState = new Map(); 119 const permissions: Array<Permissions> = [ 120 'ohos.permission.MEDIA_LOCATION', 121 'ohos.permission.READ_IMAGEVIDEO', 122 'ohos.permission.WRITE_IMAGEVIDEO', 123 ]; 124 125 const atManager = abilityAccessCtrl.createAtManager(); 126 const appFlags = bundleManager.ApplicationFlag.GET_APPLICATION_INFO_DEFAULT; 127 const userId = 100; 128 const appInfo = await bundleManager.getApplicationInfo(name, appFlags, userId); 129 const tokenID = appInfo.accessTokenId; 130 for (const permission of permissions) { 131 console.info('getPermission permission: ' + permission); 132 try { 133 await atManager.grantUserGrantedPermission(tokenID, permission, 1); 134 } catch (error) { 135 console.error(`getPermission ${permission} failed`); 136 } 137 permissionState.set(permission, await atManager.verifyAccessToken(tokenID, permission)); 138 } 139 permissionState.forEach((value, key, map) => { 140 if (value !== 0) { 141 console.info(`getPermission failed; permission: ${key}, state: ${value}`); 142 } 143 }); 144 console.info('getPermission end'); 145 } catch (error) { 146 console.error(`getPermission failed, error: ${error}`); 147 } 148}; 149 150export function isNum(value) : boolean { 151 return typeof value === 'number' && !isNaN(value); 152}; 153 154export function getAssetId(uri) : string { 155 const tag = 'Photo/'; 156 const index = uri.indexOf(tag); 157 let str = uri.substring(index + tag.length); 158 console.info(`getAssetId str: ${str}`); 159 return str; 160} 161 162export function getAlbumId(uri) : string { 163 const index = uri.lastIndexOf('/'); 164 let str = uri.substring(index + 1); 165 console.info(`getAlbumId str: ${str}`); 166 return str; 167} 168 169export function genRadomStr(len: number) : string { 170 const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 171 let randomStr = ''; 172 for (let i = 0; i < len; i++) { 173 randomStr += chars.charAt(Math.floor(Math.random() * chars.length)); 174 } 175 return randomStr; 176} 177 178export async function createUserAlbum(testNum, albumName) : Promise<photoAccessHelper.Album> { 179 console.info(`${testNum} createUserAlbum albumName: ${albumName}`); 180 let album: photoAccessHelper.Album; 181 try { 182 const helper = photoAccessHelper.getPhotoAccessHelper(globalThis.abilityContext); 183 album = await helper.createAlbum(albumName); 184 console.info(`${testNum} createUserAlbum suc`); 185 } catch (error) { 186 console.error(`Failed to createUserAlbum! error: ${error}`); 187 throw error; 188 } 189 190 return new Promise((resolve, reject) => { 191 resolve(album); 192 }); 193} 194 195export async function getFileAsset(testNum, fetchOps) : Promise<photoAccessHelper.PhotoAsset> { 196 let asset: photoAccessHelper.PhotoAsset; 197 try { 198 const helper = photoAccessHelper.getPhotoAccessHelper(globalThis.abilityContext); 199 let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset>; 200 fetchResult = await helper.getAssets(fetchOps); 201 console.info(`${testNum} getFileAsset fetchResult: ${fetchResult.getCount()}`); 202 asset = await fetchResult.getFirstObject(); 203 fetchResult.close(); 204 } catch (error) { 205 console.error(`${testNum} getFileAsset error: ${error}`); 206 throw error; 207 } 208 209 return new Promise((resolve, reject) => { 210 resolve(asset); 211 }); 212} 213 214export function getFileAssetFetchResult() : photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> { 215 let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset>; 216 return fetchResult; 217} 218 219export function getAlbumFetchResult() : photoAccessHelper.FetchResult<photoAccessHelper.Album> { 220 let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.Album>; 221 return fetchResult; 222} 223 224export function checkUserAlbum(expect, testNum, album, expectedName, expectedCover) : void { 225 console.info(`${testNum} checkUserAlbum album.albumName: ${album.albumName}, expectedName: ${expectedName}`); 226 expect(album.albumType).assertEqual(albumType.USER); 227 expect(album.albumSubtype).assertEqual(albumSubtype.USER_GENERIC); 228 expect(album.albumName).assertEqual(expectedName); 229 if (expectedCover === '') { 230 expect(album.coverUri).assertEqual(''); 231 } else { 232 expect(album.coverUri).assertEqual(expectedCover); 233 } 234 expect(album.albumUri !== '').assertEqual(true); 235 expect(album.count).assertEqual(0); 236} 237 238export function checkSystemAlbum(expect, testNum, album, expectedSubType) : void { 239 try { 240 console.info(`${testNum} checkSystemAlbum expectedSubType: ${expectedSubType}`); 241 expect(album.albumType).assertEqual(albumType.SYSTEM); 242 expect(album.albumSubtype).assertEqual(expectedSubType); 243 expect(album.albumName).assertEqual(''); 244 expect(album.albumUri !== '').assertEqual(true); 245 } catch (error) { 246 console.error(`Failed to delete all user albums! error: ${error}`); 247 throw error; 248 } 249} 250 251export async function startAbility(bundleName: string, abilityName: string) : Promise<void> { 252 await delegator.executeShellCommand(`aa start -b ${bundleName} -a ${abilityName}`).then(result => { 253 console.info(`[picker] start abilityFinished: ${result}`); 254 }).catch(err => { 255 console.error(`[picker] start abilityFailed: ${err}`); 256 }); 257} 258 259export async function stopAbility(bundleName: string) : Promise<void> { 260 await delegator.executeShellCommand(`aa force-stop ${bundleName}`).then(result => { 261 console.info(`[picker] stop abilityFinished: ${result}`); 262 }).catch(err => { 263 console.error(`[picker] stop abilityFailed: ${err}`); 264 }); 265} 266 267export async function getFileNameArray() { 268 try{ 269 let listFileOption: ListFileOptions = { 270 recursion: true, 271 listNum: 0, 272 filter: { 273 suffix: [], 274 } 275 } 276 listFileOption.filter.suffix = validImageExt.concat(validVideoExt); 277 let nameArray = await fs.listFile(pathDir, listFileOption) 278 return nameArray; 279 } catch (err) { 280 console.error('getFileNameArray failed: ' + err); 281 } 282} 283 284export async function getAllFileNameArray() { 285 try{ 286 let listFileOption: ListFileOptions = { 287 recursion: true, 288 listNum: 0, 289 filter: { 290 suffix: [], 291 } 292 } 293 listFileOption.filter.suffix = validImageExt.concat(validVideoExt).concat(validVideoMpegExt).concat(validImageGifExt).concat(validImagePngExt); 294 let nameArray = await fs.listFile(pathDir, listFileOption) 295 return nameArray; 296 } catch (err) { 297 console.error('getFileNameArray failed: ' + err); 298 } 299} 300 301export async function pushCreateAsset(names: Array<string>){ 302 console.info('pushCreateAsset start') 303 let successNum = 0; 304 try{ 305 console.info('pushCreateAsset name: ' + names) 306 let photoType: photoAccessHelper.PhotoType; 307 let resourceType: photoAccessHelper.ResourceType; 308 let fileNames: string[] = await getFileNameArray(); 309 console.info('pushCreateAsset rawFiles number: ' + fileNames.length); 310 for(let i = 0; i < fileNames.length; i++) { 311 let fileName = fileNames[i]; 312 let filePath = pathDir + '/' + fileName; 313 let fileUri = fileuri.getUriFromPath(filePath); 314 let rawExtension: string = fileName.split('.')[1]; 315 for (let j = 0; j < names.length; j++) { 316 let name = names[j]; 317 if (fileName.includes('error')) continue 318 let extension: string = name.split('.')[1]; 319 if (rawExtension === extension) { 320 let options: photoAccessHelper.CreateOptions = { 321 title: name.split('.')[0] 322 } 323 if (validImageExt.includes(('.' + extension))) { 324 photoType = photoAccessHelper.PhotoType.IMAGE; 325 resourceType = photoAccessHelper.ResourceType.IMAGE_RESOURCE; 326 } else { 327 photoType = photoAccessHelper.PhotoType.VIDEO; 328 resourceType = photoAccessHelper.ResourceType.VIDEO_RESOURCE; 329 } 330 let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest = photoAccessHelper.MediaAssetChangeRequest.createAssetRequest(globalThis.abilityContext, photoType, extension, options); 331 assetChangeRequest.addResource(resourceType, fileUri); 332 await phAccessHelper.applyChanges(assetChangeRequest); 333 console.info(`pushCreateAsset ${name} create success`) 334 successNum++; 335 } 336 } 337 } 338 console.info('Push_createAsset successfully fileNumber: ' + successNum); 339 }catch(err){ 340 console.error('Push_createAsset push resource failed: ' + err) 341 return; 342 } 343} 344 345export async function pushCreateAssetSingle(names: Array<string>){ 346 console.info('pushCreateAssetSingle start') 347 let successNum = 0; 348 try{ 349 console.info('pushCreateAssetSingle name: ' + names) 350 let photoType: photoAccessHelper.PhotoType; 351 let resourceType: photoAccessHelper.ResourceType; 352 let fileNames: string[] = await getAllFileNameArray(); 353 for (let i = 0; i < fileNames.length; i++) { 354 let fileName = fileNames[i]; 355 let filePath = pathDir + '/' + fileName; 356 let fileUri = fileuri.getUriFromPath(filePath); 357 let rawExtension: string = fileName.split('.')[1]; 358 for (let j = 0; j < names.length; j++) { 359 let name = names[j]; 360 if(fileName == '/01.jpg' || fileName == '/01.mp4') continue 361 let extension: string = name.split('.')[1]; 362 if (rawExtension === extension) { 363 let options: photoAccessHelper.CreateOptions = { 364 title: name.split('.')[0] 365 } 366 if (validImageExt.concat(validImageGifExt).concat(validImagePngExt).includes(('.' + extension))) { 367 photoType = photoAccessHelper.PhotoType.IMAGE; 368 resourceType = photoAccessHelper.ResourceType.IMAGE_RESOURCE; 369 } else { 370 photoType = photoAccessHelper.PhotoType.VIDEO; 371 resourceType = photoAccessHelper.ResourceType.VIDEO_RESOURCE; 372 } 373 let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest = photoAccessHelper.MediaAssetChangeRequest.createAssetRequest(globalThis.abilityContext, photoType, extension, options); 374 assetChangeRequest.addResource(resourceType, fileUri); 375 await phAccessHelper.applyChanges(assetChangeRequest); 376 console.info(`pushCreateAssetSingle ${name} create success`) 377 successNum++; 378 } 379 } 380 } 381 console.info('Push_createAsset successfully fileNumber: ' + successNum); 382 }catch(err){ 383 console.error('Push_createAsset push resource failed: ' + err) 384 return; 385 } 386} 387 388export function createSandboxFileUri(extension) { 389 let pathDir = globalThis.abilityContext.filesDir; 390 let path = pathDir + '/test' + new Date().getTime() + '.' + extension; 391 fs.openSync(path, fs.OpenMode.CREATE) 392 return fileuri.getUriFromPath(path); 393} 394 395export async function getBurstKey(testNum: string, fetchOps: photoAccessHelper.FetchOptions): Promise<string | number> { 396 let burstKey: string | number | undefined = -1; 397 try { 398 let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> = await phAccessHelper.getAssets(fetchOps); 399 if (fetchResult === undefined) { 400 console.error(`${testNum} :: getBurstKey :: fetchResult is undefined !`); 401 return burstKey; 402 } 403 let photoAsset: photoAccessHelper.PhotoAsset = await fetchResult.getFirstObject(); 404 if (photoAsset === undefined) { 405 console.error(`${testNum} :: getBurstKey :: photoAsset is undefined !`); 406 return burstKey; 407 } 408 burstKey = photoAsset.get(photoKeys.BURST_KEY).toString(); 409 console.log(`${testNum} :: get burstKey success, burstKey is ${burstKey}`); 410 return burstKey; 411 } catch (error) { 412 console.error(`${testNum} :: getBurstKey failed, msg is ${error}`); 413 return burstKey; 414 } 415} 416 417export { 418 photoType, 419 photoKeys, 420 albumKeys, 421 albumType, 422 albumSubtype, 423};