1 /*
2 * Copyright (c) 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
16 #include "media_asset_change_request_impl.h"
17
18 #include <sys/sendfile.h>
19
20 #include "ability_runtime/cj_ability_context.h"
21 #include "access_token.h"
22 #include "accesstoken_kit.h"
23 #include "datashare_helper.h"
24 #include "datashare_predicates.h"
25 #include "delete_callback.h"
26 #include "directory_ex.h"
27 #include "file_uri.h"
28 #include "image_packer.h"
29 #include "media_file_utils.h"
30 #include "permission_utils.h"
31 #include "userfile_manager_types.h"
32
33 using namespace OHOS::Security::AccessToken;
34
35 namespace OHOS {
36 namespace Media {
37 constexpr int64_t CREATE_ASSET_REQUEST_PENDING = -4;
38 constexpr int32_t MAX_DELETE_NUMBER = 300;
39 const std::string DEFAULT_TITLE_TIME_FORMAT = "%Y%m%d_%H%M%S";
40 const std::string DEFAULT_TITLE_IMG_PREFIX = "IMG_";
41 const std::string DEFAULT_TITLE_VIDEO_PREFIX = "VID_";
42 const std::string MOVING_PHOTO_VIDEO_EXTENSION = "mp4";
43 std::atomic<uint32_t> MediaAssetChangeRequestImpl::cacheFileId_ = 0;
44
45 static const std::array<int, 4> ORIENTATION_ARRAY = { 0, 90, 180, 270 };
46
ReadData(const std::shared_ptr<AVSharedMemory> & mem,uint32_t length)47 int32_t MediaDataSource::ReadData(const std::shared_ptr<AVSharedMemory>& mem, uint32_t length)
48 {
49 if (readPos_ >= size_) {
50 LOGE("Failed to check read position");
51 return SOURCE_ERROR_EOF;
52 }
53
54 if (memcpy_s(mem->GetBase(), mem->GetSize(), (char*)buffer_ + readPos_, length) != E_OK) {
55 LOGE("Failed to copy buffer to mem");
56 return SOURCE_ERROR_IO;
57 }
58 readPos_ += static_cast<int64_t>(length);
59 return static_cast<int32_t>(length);
60 }
61
ReadAt(const std::shared_ptr<AVSharedMemory> & mem,uint32_t length,int64_t pos)62 int32_t MediaDataSource::ReadAt(const std::shared_ptr<AVSharedMemory>& mem, uint32_t length, int64_t pos)
63 {
64 readPos_ = pos;
65 return ReadData(mem, length);
66 }
67
ReadAt(int64_t pos,uint32_t length,const std::shared_ptr<AVSharedMemory> & mem)68 int32_t MediaDataSource::ReadAt(int64_t pos, uint32_t length, const std::shared_ptr<AVSharedMemory>& mem)
69 {
70 readPos_ = pos;
71 return ReadData(mem, length);
72 }
73
ReadAt(uint32_t length,const std::shared_ptr<AVSharedMemory> & mem)74 int32_t MediaDataSource::ReadAt(uint32_t length, const std::shared_ptr<AVSharedMemory>& mem)
75 {
76 return ReadData(mem, length);
77 }
78
GetSize(int64_t & size)79 int32_t MediaDataSource::GetSize(int64_t& size)
80 {
81 size = size_;
82 return E_OK;
83 }
84
GetFileAssetInstance() const85 std::shared_ptr<FileAsset> MediaAssetChangeRequestImpl::GetFileAssetInstance() const
86 {
87 return fileAsset_;
88 }
89
MediaAssetChangeRequestImpl(std::shared_ptr<FileAsset> fileAssetPtr)90 MediaAssetChangeRequestImpl::MediaAssetChangeRequestImpl(std::shared_ptr<FileAsset> fileAssetPtr)
91 {
92 fileAsset_ = fileAssetPtr;
93 }
94
ParseFileUri(const std::string & fileUriStr,MediaType mediaType,std::string & realPath)95 static bool ParseFileUri(const std::string& fileUriStr, MediaType mediaType, std::string& realPath)
96 {
97 AppFileService::ModuleFileUri::FileUri fileUri(fileUriStr);
98 std::string path = fileUri.GetRealPath();
99 if (!PathToRealPath(path, realPath)) {
100 return false;
101 }
102 if (mediaType != MediaFileUtils::GetMediaType(realPath)) {
103 return false;
104 }
105 return true;
106 }
107
CheckMovingPhotoCreationArgs(DataShare::DataShareValuesBucket valuesBucket)108 static bool CheckMovingPhotoCreationArgs(DataShare::DataShareValuesBucket valuesBucket)
109 {
110 bool isValid = false;
111 int32_t mediaType = valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
112 if (!isValid) {
113 return false;
114 }
115 if (mediaType != static_cast<int32_t>(MEDIA_TYPE_IMAGE)) {
116 return false;
117 }
118 std::string extension = valuesBucket.Get(ASSET_EXTENTION, isValid);
119 if (isValid) {
120 return MediaFileUtils::CheckMovingPhotoExtension(extension);
121 }
122
123 std::string displayName = valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
124 return isValid && MediaFileUtils::CheckMovingPhotoExtension(MediaFileUtils::GetExtensionFromPath(displayName));
125 }
126
CheckCreateOption(DataShare::DataShareValuesBucket valuesBucket,bool isSystemApi)127 static bool CheckCreateOption(DataShare::DataShareValuesBucket valuesBucket, bool isSystemApi)
128 {
129 bool isValid = false;
130 int32_t subType = valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
131 if (isValid) {
132 if (subType < static_cast<int32_t>(PhotoSubType::DEFAULT) ||
133 subType >= static_cast<int32_t>(PhotoSubType::SUBTYPE_END)) {
134 return false;
135 }
136 if (subType == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO) &&
137 !CheckMovingPhotoCreationArgs(valuesBucket)) {
138 return false;
139 }
140 if (!isSystemApi && subType != static_cast<int32_t>(PhotoSubType::DEFAULT) &&
141 subType != static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)) {
142 return false;
143 }
144 }
145 std::string cameraShotKey = valuesBucket.Get(PhotoColumn::CAMERA_SHOT_KEY, isValid);
146 if (isValid) {
147 if (cameraShotKey.size() < CAMERA_SHOT_KEY_SIZE) {
148 return false;
149 }
150 if (subType == static_cast<int32_t>(PhotoSubType::SCREENSHOT)) {
151 return false;
152 } else {
153 valuesBucket.Put(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::CAMERA));
154 }
155 }
156 return true;
157 }
158
MediaAssetChangeRequestImpl(int64_t contextId,int32_t photoType,std::string extension,std::string title,int32_t subType,int32_t * errCode)159 MediaAssetChangeRequestImpl::MediaAssetChangeRequestImpl(
160 int64_t contextId, int32_t photoType, std::string extension, std::string title, int32_t subType, int32_t* errCode)
161 {
162 DataShare::DataShareValuesBucket valuesBucket;
163 if (!MediaAssetChangeRequestImpl::InitUserFileClient(contextId)) {
164 *errCode = JS_INNER_FAIL;
165 return;
166 }
167 MediaType mediaType = static_cast<MediaType>(photoType);
168 if (mediaType != MEDIA_TYPE_IMAGE && mediaType != MEDIA_TYPE_VIDEO &&
169 mediaType != MediaFileUtils::GetMediaType("." + extension)) {
170 LOGE("Invalid photoType or failed to check extension");
171 *errCode = OHOS_INVALID_PARAM_CODE;
172 return;
173 }
174 valuesBucket.Put(ASSET_EXTENTION, extension);
175 valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
176 if (!title.empty()) {
177 valuesBucket.Put(PhotoColumn::MEDIA_TITLE, title);
178 }
179 if (subType != -1) {
180 valuesBucket.Put(PhotoColumn::PHOTO_SUBTYPE, subType);
181 }
182 if (!CheckCreateOption(valuesBucket, false)) {
183 *errCode = OHOS_INVALID_PARAM_CODE;
184 return;
185 }
186 bool isValid = false;
187 std::string newTitle = valuesBucket.Get(PhotoColumn::MEDIA_TITLE, isValid);
188 if (!isValid) {
189 newTitle = mediaType == MEDIA_TYPE_IMAGE ? DEFAULT_TITLE_IMG_PREFIX : DEFAULT_TITLE_VIDEO_PREFIX;
190 newTitle += MediaFileUtils::StrCreateTime(DEFAULT_TITLE_TIME_FORMAT, MediaFileUtils::UTCTimeSeconds());
191 valuesBucket.Put(PhotoColumn::MEDIA_TITLE, newTitle);
192 }
193 std::string displayName = newTitle + "." + extension;
194 if (MediaFileUtils::CheckDisplayName(displayName) != E_OK) {
195 *errCode = OHOS_INVALID_PARAM_CODE;
196 return;
197 }
198 valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
199 auto emptyFileAsset = std::make_unique<FileAsset>();
200 emptyFileAsset->SetDisplayName(displayName);
201 emptyFileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
202 emptyFileAsset->SetMediaType(MediaFileUtils::GetMediaType(displayName));
203 emptyFileAsset->SetPhotoSubType(subType);
204 emptyFileAsset->SetTimePending(CREATE_ASSET_REQUEST_PENDING);
205 emptyFileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
206 fileAsset_ = std::move(emptyFileAsset);
207 creationValuesBucket_ = std::move(valuesBucket);
208 RecordChangeOperation(AssetChangeOperation::CREATE_FROM_SCRATCH);
209 }
210
ParseArgsDeleteAssets(int64_t contextId,std::vector<std::string> uris)211 static int32_t ParseArgsDeleteAssets(int64_t contextId, std::vector<std::string> uris)
212 {
213 if (!MediaAssetChangeRequestImpl::InitUserFileClient(contextId)) {
214 return JS_INNER_FAIL;
215 }
216 if (uris.empty()) {
217 LOGE("Failed to check empty array");
218 return OHOS_INVALID_PARAM_CODE;
219 }
220 for (const auto& uri : uris) {
221 if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == std::string::npos) {
222 return JS_E_URI;
223 }
224 }
225 return 0;
226 }
227
GetAssetChangeOperations() const228 std::vector<AssetChangeOperation> MediaAssetChangeRequestImpl::GetAssetChangeOperations() const
229 {
230 return assetChangeOperations_;
231 }
232
GetAddResourceTypes() const233 std::vector<ResourceType> MediaAssetChangeRequestImpl::GetAddResourceTypes() const
234 {
235 return addResourceTypes_;
236 }
237
HasWritePermission()238 static bool HasWritePermission()
239 {
240 AccessTokenID tokenCaller = IPCSkeleton::GetSelfTokenID();
241 int result = AccessTokenKit::VerifyAccessToken(tokenCaller, PERM_WRITE_IMAGEVIDEO);
242 return result == PermissionState::PERMISSION_GRANTED;
243 }
244
InitDeleteRequest(std::string & appName,std::vector<std::string> & uris,OHOS::AAFwk::Want & request,std::shared_ptr<DeleteCallback> & callback)245 static bool InitDeleteRequest(std::string& appName, std::vector<std::string>& uris, OHOS::AAFwk::Want& request,
246 std::shared_ptr<DeleteCallback>& callback)
247 {
248 request.SetElementName(DELETE_UI_PACKAGE_NAME, DELETE_UI_EXT_ABILITY_NAME);
249 request.SetParam(DELETE_UI_EXTENSION_TYPE, DELETE_UI_REQUEST_TYPE);
250
251 if (appName.empty()) {
252 return false;
253 }
254 request.SetParam(DELETE_UI_APPNAME, appName);
255
256 request.SetParam(DELETE_UI_URIS, uris);
257 callback->SetUris(uris);
258 return true;
259 }
260
DeleteAssetsExecute(OHOS::DataShare::DataSharePredicates & predicates,OHOS::DataShare::DataShareValuesBucket & valuesBucket)261 static int32_t DeleteAssetsExecute(OHOS::DataShare::DataSharePredicates& predicates,
262 OHOS::DataShare::DataShareValuesBucket& valuesBucket)
263 {
264 std::string trashUri = PAH_SYS_TRASH_PHOTO;
265 MediaLibraryNapiUtils::UriAppendKeyValue(trashUri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
266 Uri updateAssetUri(trashUri);
267 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
268 if (changedRows < 0) {
269 LOGE("Failed to delete assets, err: %{public}d", changedRows);
270 return changedRows;
271 }
272 return 0;
273 }
274
SetSessionId(std::string & appName,std::vector<std::string> & uris,Ace::UIContent * uiContent,std::shared_ptr<DeleteCallback> & callback,Ace::ModalUIExtensionCallbacks & extensionCallback)275 static int32_t SetSessionId(std::string &appName, std::vector<std::string> &uris, Ace::UIContent* uiContent,
276 std::shared_ptr<DeleteCallback>& callback, Ace::ModalUIExtensionCallbacks &extensionCallback)
277 {
278 OHOS::AAFwk::Want request;
279 if (!InitDeleteRequest(appName, uris, request, callback)) {
280 return JS_INNER_FAIL;
281 }
282 OHOS::Ace::ModalUIExtensionConfig config;
283 config.isProhibitBack = true;
284 int32_t sessionId = uiContent->CreateModalUIExtension(request, extensionCallback, config);
285 if (sessionId == 0) {
286 return JS_INNER_FAIL;
287 }
288 callback->SetSessionId(sessionId);
289 return 0;
290 }
291
CJDeleteAssets(int64_t contextId,std::vector<std::string> uris)292 int32_t MediaAssetChangeRequestImpl::CJDeleteAssets(int64_t contextId, std::vector<std::string> uris)
293 {
294 if (ParseArgsDeleteAssets(contextId, uris) != 0) {
295 return OHOS_INVALID_PARAM_CODE;
296 }
297 OHOS::DataShare::DataSharePredicates predicates;
298 OHOS::DataShare::DataShareValuesBucket valuesBucket;
299 predicates.In(PhotoColumn::MEDIA_ID, uris);
300 valuesBucket.Put(PhotoColumn::MEDIA_DATE_TRASHED, MediaFileUtils::UTCTimeSeconds());
301 if (MediaLibraryNapiUtils::IsSystemApp()) {
302 DeleteAssetsExecute(predicates, valuesBucket);
303 }
304 #ifdef HAS_ACE_ENGINE_PART
305 if (!HasWritePermission()) {
306 return OHOS_PERMISSION_DENIED_CODE;
307 }
308 if (uris.size() > MAX_DELETE_NUMBER) {
309 LOGE("No more than 300 assets can be deleted at one time");
310 return OHOS_INVALID_PARAM_CODE;
311 }
312 auto cjAbilityContext = FFI::FFIData::GetData<AbilityRuntime::CJAbilityContext>(contextId);
313 if (cjAbilityContext == nullptr || cjAbilityContext->GetAbilityContext() == nullptr) {
314 LOGE("Failed to get native stage context instance");
315 return JS_INNER_FAIL;
316 }
317 auto abilityContext = cjAbilityContext->GetAbilityContext();
318 auto abilityInfo = abilityContext->GetAbilityInfo();
319 std::string appName;
320 abilityContext->GetResourceManager()->GetStringById(abilityInfo->labelId, appName);
321 auto uiContent = abilityContext->GetUIContent();
322 if (uiContent == nullptr) {
323 return JS_INNER_FAIL;
324 }
325 auto callback = std::make_shared<DeleteCallback>(uiContent);
326 OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
327 [callback](int32_t releaseCode) { callback->OnRelease(releaseCode); },
328 [callback](int32_t resultCode, const AAFwk::Want& result) { callback->OnResult(resultCode, result); },
329 [callback](const OHOS::AAFwk::WantParams& request) { callback->OnReceive(request); },
330 [callback](int32_t code, const std::string& name, const std::string& message) {
331 callback->OnError(code, name, message);
332 },
333 };
334 return SetSessionId(appName, uris, uiContent, callback, extensionCallback);
335 #else
336 LOGE("ace_engine is not support");
337 return JS_INNER_FAIL;
338 #endif
339 }
340
CJGetAsset(int32_t * errCode)341 int64_t MediaAssetChangeRequestImpl::CJGetAsset(int32_t* errCode)
342 {
343 if (fileAsset_ == nullptr) {
344 *errCode = JS_INNER_FAIL;
345 return 0;
346 }
347 if (fileAsset_->GetId() > 0) {
348 auto photoAssetImpl = FFIData::Create<PhotoAssetImpl>(fileAsset_);
349 if (!photoAssetImpl) {
350 *errCode = JS_INNER_FAIL;
351 return 0;
352 }
353 return photoAssetImpl->GetID();
354 }
355 return 0;
356 }
357
MediaAssetChangeRequestImpl(int64_t contextId,const std::string & filePath,MediaType meidiaType,int32_t * errCode)358 MediaAssetChangeRequestImpl::MediaAssetChangeRequestImpl(
359 int64_t contextId, const std::string& filePath, MediaType meidiaType, int32_t* errCode)
360 {
361 if (!MediaAssetChangeRequestImpl::InitUserFileClient(contextId)) {
362 *errCode = JS_INNER_FAIL;
363 return;
364 }
365 std::string realPath;
366 if ((meidiaType == MediaType::MEDIA_TYPE_IMAGE && ParseFileUri(filePath, MediaType::MEDIA_TYPE_IMAGE, realPath)) ||
367 (meidiaType == MediaType::MEDIA_TYPE_VIDEO && ParseFileUri(filePath, MediaType::MEDIA_TYPE_VIDEO, realPath))) {
368 std::string displayName = MediaFileUtils::GetFileName(realPath);
369 if (MediaFileUtils::CheckDisplayName(displayName) != E_OK) {
370 *errCode = OHOS_INVALID_PARAM_CODE;
371 return;
372 }
373 std::string title = MediaFileUtils::GetTitleFromDisplayName(displayName);
374 MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
375 auto emptyFileAsset = std::make_unique<FileAsset>();
376 emptyFileAsset->SetDisplayName(displayName);
377 emptyFileAsset->SetTitle(title);
378 emptyFileAsset->SetMediaType(mediaType);
379 emptyFileAsset->SetPhotoSubType(static_cast<int32_t>(PhotoSubType::DEFAULT));
380 emptyFileAsset->SetTimePending(CREATE_ASSET_REQUEST_PENDING);
381 emptyFileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
382 fileAsset_ = std::move(emptyFileAsset);
383 realPath_ = realPath;
384 creationValuesBucket_.Put(MEDIA_DATA_DB_NAME, displayName);
385 creationValuesBucket_.Put(ASSET_EXTENTION, MediaFileUtils::GetExtensionFromPath(displayName));
386 creationValuesBucket_.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
387 creationValuesBucket_.Put(PhotoColumn::MEDIA_TITLE, title);
388 RecordChangeOperation(AssetChangeOperation::CREATE_FROM_URI);
389 return;
390 }
391 *errCode = OHOS_INVALID_PARAM_CODE;
392 return;
393 }
394
RecordChangeOperation(AssetChangeOperation changeOperation)395 void MediaAssetChangeRequestImpl::RecordChangeOperation(AssetChangeOperation changeOperation)
396 {
397 if ((changeOperation == AssetChangeOperation::GET_WRITE_CACHE_HANDLER ||
398 changeOperation == AssetChangeOperation::ADD_RESOURCE ||
399 changeOperation == AssetChangeOperation::ADD_FILTERS) &&
400 Contains(AssetChangeOperation::CREATE_FROM_SCRATCH)) {
401 assetChangeOperations_.insert(assetChangeOperations_.begin() + 1, changeOperation);
402 return;
403 }
404 if (changeOperation == AssetChangeOperation::ADD_RESOURCE &&
405 Contains(AssetChangeOperation::SET_MOVING_PHOTO_EFFECT_MODE)) {
406 assetChangeOperations_.insert(assetChangeOperations_.begin(), changeOperation);
407 return;
408 }
409 assetChangeOperations_.push_back(changeOperation);
410 }
411
Contains(AssetChangeOperation changeOperation) const412 bool MediaAssetChangeRequestImpl::Contains(AssetChangeOperation changeOperation) const
413 {
414 return std::find(assetChangeOperations_.begin(), assetChangeOperations_.end(), changeOperation) !=
415 assetChangeOperations_.end();
416 }
417
FetchAddCacheFileId()418 uint32_t MediaAssetChangeRequestImpl::FetchAddCacheFileId()
419 {
420 uint32_t id = cacheFileId_.fetch_add(1);
421 return id;
422 }
423
SetCacheFileName(std::string & fileName)424 void MediaAssetChangeRequestImpl::SetCacheFileName(std::string& fileName)
425 {
426 cacheFileName_ = fileName;
427 }
428
SetCacheMovingPhotoVideoName(std::string & fileName)429 void MediaAssetChangeRequestImpl::SetCacheMovingPhotoVideoName(std::string& fileName)
430 {
431 cacheMovingPhotoVideoName_ = fileName;
432 }
433
GetMovingPhotoVideoPath() const434 std::string MediaAssetChangeRequestImpl::GetMovingPhotoVideoPath() const
435 {
436 return movingPhotoVideoRealPath_;
437 }
438
GetFileRealPath() const439 std::string MediaAssetChangeRequestImpl::GetFileRealPath() const
440 {
441 return realPath_;
442 }
443
GetAddResourceMode() const444 AddResourceMode MediaAssetChangeRequestImpl::GetAddResourceMode() const
445 {
446 return addResourceMode_;
447 }
448
GetDataBuffer() const449 void* MediaAssetChangeRequestImpl::GetDataBuffer() const
450 {
451 return dataBuffer_;
452 }
453
GetDataBufferSize() const454 size_t MediaAssetChangeRequestImpl::GetDataBufferSize() const
455 {
456 return dataBufferSize_;
457 }
458
GetMovingPhotoVideoMode() const459 AddResourceMode MediaAssetChangeRequestImpl::GetMovingPhotoVideoMode() const
460 {
461 return movingPhotoVideoResourceMode_;
462 }
463
GetMovingPhotoVideoBuffer() const464 void* MediaAssetChangeRequestImpl::GetMovingPhotoVideoBuffer() const
465 {
466 return movingPhotoVideoDataBuffer_;
467 }
468
GetMovingPhotoVideoSize() const469 size_t MediaAssetChangeRequestImpl::GetMovingPhotoVideoSize() const
470 {
471 return movingPhotoVideoBufferSize_;
472 }
473
GetPhotoProxyObj()474 sptr<PhotoProxy> MediaAssetChangeRequestImpl::GetPhotoProxyObj()
475 {
476 return photoProxy_;
477 }
478
ReleasePhotoProxyObj()479 void MediaAssetChangeRequestImpl::ReleasePhotoProxyObj()
480 {
481 photoProxy_->Release();
482 photoProxy_ = nullptr;
483 }
484
GetImageFileType()485 int32_t MediaAssetChangeRequestImpl::GetImageFileType()
486 {
487 return imageFileType_;
488 }
489
CreateAssetBySecurityComponent(std::string & assetUri)490 int32_t MediaAssetChangeRequestImpl::CreateAssetBySecurityComponent(std::string& assetUri)
491 {
492 bool isValid = false;
493 std::string title = creationValuesBucket_.Get(PhotoColumn::MEDIA_TITLE, isValid);
494 if (!isValid) {
495 LOGE("Failed to get title");
496 return E_FAIL;
497 }
498 std::string extension = creationValuesBucket_.Get(ASSET_EXTENTION, isValid);
499 if (!isValid || MediaFileUtils::CheckDisplayName(title + "." + extension) != E_OK) {
500 LOGE("Failed to check displayName");
501 return E_FAIL;
502 }
503 creationValuesBucket_.valuesMap.erase(MEDIA_DATA_DB_NAME);
504
505 std::string uri = PAH_CREATE_PHOTO_COMPONENT; // create asset by security component
506 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
507 Uri createAssetUri(uri);
508 return UserFileClient::InsertExt(createAssetUri, creationValuesBucket_, assetUri);
509 }
510
PutMediaAssetEditData(DataShare::DataShareValuesBucket & valuesBucket)511 int32_t MediaAssetChangeRequestImpl::PutMediaAssetEditData(DataShare::DataShareValuesBucket& valuesBucket)
512 {
513 if (editData_ == nullptr) {
514 return E_OK;
515 }
516
517 std::string compatibleFormat = editData_->GetCompatibleFormat();
518 if (compatibleFormat.empty()) {
519 LOGE("Failed to check compatibleFormat");
520 return E_FAIL;
521 }
522 std::string formatVersion = editData_->GetFormatVersion();
523 if (formatVersion.empty()) {
524 LOGE("Failed to check formatVersion");
525 return E_FAIL;
526 }
527 std::string data = editData_->GetData();
528 if (data.empty()) {
529 LOGE("Failed to check data");
530 return E_FAIL;
531 }
532
533 valuesBucket.Put(COMPATIBLE_FORMAT, compatibleFormat);
534 valuesBucket.Put(FORMAT_VERSION, formatVersion);
535 valuesBucket.Put(EDIT_DATA, data);
536 return E_OK;
537 }
538
CopyToMediaLibrary(bool isCreation,AddResourceMode mode)539 int32_t MediaAssetChangeRequestImpl::CopyToMediaLibrary(bool isCreation, AddResourceMode mode)
540 {
541 if (fileAsset_ == nullptr) {
542 LOGE("Failed to check fileAsset_");
543 return E_FAIL;
544 }
545 int32_t ret = E_ERR;
546 int32_t id = 0;
547 std::string assetUri;
548 if (isCreation) {
549 ret = CreateAssetBySecurityComponent(assetUri);
550 if (ret <= 0) {
551 LOGE("Failed to create asset by security component");
552 return ret == 0 ? E_ERR : ret;
553 }
554 id = ret;
555 } else {
556 assetUri = fileAsset_->GetUri();
557 }
558 if (assetUri.empty()) {
559 LOGE("Failed to check empty asset uri");
560 return E_ERR;
561 }
562
563 if (IsMovingPhoto()) {
564 ret = CopyMovingPhotoVideo(assetUri);
565 if (ret != E_OK) {
566 LOGE("Failed to copy data to moving photo video with error: %{public}d", ret);
567 return ret;
568 }
569 }
570
571 Uri uri(assetUri);
572 UniqueFd destFd(UserFileClient::OpenFile(uri, MEDIA_FILEMODE_WRITEONLY));
573 if (destFd.Get() < 0) {
574 LOGE("Failed to open %{private}s with error: %{public}d", assetUri.c_str(), destFd.Get());
575 return destFd.Get();
576 }
577
578 if (mode == AddResourceMode::FILE_URI) {
579 ret = CopyFileToMediaLibrary(destFd);
580 } else if (mode == AddResourceMode::DATA_BUFFER) {
581 ret = CopyDataBufferToMediaLibrary(destFd);
582 } else {
583 LOGE("Invalid mode: %{public}d", mode);
584 return E_INVALID_VALUES;
585 }
586
587 if (ret == E_OK && isCreation) {
588 SetNewFileAsset(id, assetUri);
589 }
590 return ret;
591 }
592
ContainsResource(ResourceType resourceType) const593 bool MediaAssetChangeRequestImpl::ContainsResource(ResourceType resourceType) const
594 {
595 return std::find(addResourceTypes_.begin(), addResourceTypes_.end(), resourceType) != addResourceTypes_.end();
596 }
597
IsMovingPhoto() const598 bool MediaAssetChangeRequestImpl::IsMovingPhoto() const
599 {
600 return fileAsset_ != nullptr &&
601 (fileAsset_->GetPhotoSubType() == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO) ||
602 (fileAsset_->GetPhotoSubType() == static_cast<int32_t>(PhotoSubType::DEFAULT) &&
603 fileAsset_->GetMovingPhotoEffectMode() == static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY)));
604 }
605
CheckMovingPhotoResource(ResourceType resourceType) const606 bool MediaAssetChangeRequestImpl::CheckMovingPhotoResource(ResourceType resourceType) const
607 {
608 if (resourceType == ResourceType::INVALID_RESOURCE) {
609 LOGE("Invalid resource type");
610 return false;
611 }
612
613 bool isResourceTypeVaild = !ContainsResource(resourceType);
614 int addResourceTimes =
615 std::count(assetChangeOperations_.begin(), assetChangeOperations_.end(), AssetChangeOperation::ADD_RESOURCE);
616 return isResourceTypeVaild && addResourceTimes <= 1; // currently, add resource no more than once
617 }
618
619 static const std::unordered_map<MovingPhotoEffectMode, std::unordered_map<ResourceType, bool>>
620 EFFECT_MODE_RESOURCE_CHECK = {
621 { MovingPhotoEffectMode::DEFAULT,
622 { { ResourceType::IMAGE_RESOURCE, false }, { ResourceType::VIDEO_RESOURCE, false } } },
623 { MovingPhotoEffectMode::BOUNCE_PLAY,
624 { { ResourceType::IMAGE_RESOURCE, false }, { ResourceType::VIDEO_RESOURCE, true } } },
625 { MovingPhotoEffectMode::LOOP_PLAY,
626 { { ResourceType::IMAGE_RESOURCE, false }, { ResourceType::VIDEO_RESOURCE, true } } },
627 { MovingPhotoEffectMode::CINEMA_GRAPH,
628 { { ResourceType::IMAGE_RESOURCE, false }, { ResourceType::VIDEO_RESOURCE, true } } },
629 { MovingPhotoEffectMode::LONG_EXPOSURE,
630 { { ResourceType::IMAGE_RESOURCE, true }, { ResourceType::VIDEO_RESOURCE, false } } },
631 { MovingPhotoEffectMode::MULTI_EXPOSURE,
632 { { ResourceType::IMAGE_RESOURCE, true }, { ResourceType::VIDEO_RESOURCE, false } } },
633 { MovingPhotoEffectMode::IMAGE_ONLY,
634 { { ResourceType::IMAGE_RESOURCE, false }, { ResourceType::VIDEO_RESOURCE, false } } },
635 };
636
CheckEffectModeWriteOperation()637 bool MediaAssetChangeRequestImpl::CheckEffectModeWriteOperation()
638 {
639 if (fileAsset_ == nullptr) {
640 LOGE("fileAsset is nullptr");
641 return false;
642 }
643
644 if (fileAsset_->GetTimePending() != 0) {
645 LOGE("Failed to check pending of fileAsset: %{public}" PRId64, fileAsset_->GetTimePending());
646 return false;
647 }
648
649 MovingPhotoEffectMode effectMode = static_cast<MovingPhotoEffectMode>(fileAsset_->GetMovingPhotoEffectMode());
650 auto iter = EFFECT_MODE_RESOURCE_CHECK.find(effectMode);
651 if (iter == EFFECT_MODE_RESOURCE_CHECK.end()) {
652 LOGE("Failed to check effect mode: %{public}d", static_cast<int32_t>(effectMode));
653 return false;
654 }
655
656 bool isImageExist = ContainsResource(ResourceType::IMAGE_RESOURCE);
657 bool isVideoExist = ContainsResource(ResourceType::VIDEO_RESOURCE);
658 if (iter->second.at(ResourceType::IMAGE_RESOURCE) && !isImageExist) {
659 LOGE("Failed to check image resource for effect mode: %{public}d", static_cast<int32_t>(effectMode));
660 return false;
661 }
662 if (iter->second.at(ResourceType::VIDEO_RESOURCE) && !isVideoExist) {
663 LOGE("Failed to check video resource for effect mode: %{public}d", static_cast<int32_t>(effectMode));
664 return false;
665 }
666 return true;
667 }
668
CheckMovingPhotoWriteOperation()669 bool MediaAssetChangeRequestImpl::CheckMovingPhotoWriteOperation()
670 {
671 if (Contains(AssetChangeOperation::SET_MOVING_PHOTO_EFFECT_MODE)) {
672 return CheckEffectModeWriteOperation();
673 }
674
675 bool containsAddResource = Contains(AssetChangeOperation::ADD_RESOURCE);
676 if (!containsAddResource) {
677 return true;
678 }
679
680 bool isCreation = Contains(AssetChangeOperation::CREATE_FROM_SCRATCH);
681 if (!isCreation) {
682 return true;
683 }
684
685 int addResourceTimes =
686 std::count(assetChangeOperations_.begin(), assetChangeOperations_.end(), AssetChangeOperation::ADD_RESOURCE);
687 bool isImageExist = ContainsResource(ResourceType::IMAGE_RESOURCE);
688 bool isVideoExist = ContainsResource(ResourceType::VIDEO_RESOURCE);
689 return addResourceTimes == 2 && isImageExist && isVideoExist; // must add resource 2 times with image and video
690 }
691
CheckChangeOperations()692 bool MediaAssetChangeRequestImpl::CheckChangeOperations()
693 {
694 if (assetChangeOperations_.empty()) {
695 LOGE("None request to apply");
696 return false;
697 }
698
699 bool isCreateFromScratch = Contains(AssetChangeOperation::CREATE_FROM_SCRATCH);
700 bool isCreateFromUri = Contains(AssetChangeOperation::CREATE_FROM_URI);
701 bool containsEdit = Contains(AssetChangeOperation::SET_EDIT_DATA);
702 bool containsGetHandler = Contains(AssetChangeOperation::GET_WRITE_CACHE_HANDLER);
703 bool containsAddResource = Contains(AssetChangeOperation::ADD_RESOURCE);
704 bool isSaveCameraPhoto = Contains(AssetChangeOperation::SAVE_CAMERA_PHOTO);
705 if ((isCreateFromScratch || containsEdit) && !containsGetHandler && !containsAddResource && !isSaveCameraPhoto) {
706 LOGE("Cannot create or edit asset without data to write");
707 return false;
708 }
709
710 if (containsEdit && (isCreateFromScratch || isCreateFromUri)) {
711 LOGE("Cannot create together with edit");
712 return false;
713 }
714
715 auto fileAsset = GetFileAssetInstance();
716 if (fileAsset == nullptr) {
717 LOGE("fileAsset is null");
718 return false;
719 }
720
721 AssetChangeOperation firstOperation = assetChangeOperations_.front();
722 if (fileAsset->GetId() <= 0 && firstOperation != AssetChangeOperation::CREATE_FROM_SCRATCH &&
723 firstOperation != AssetChangeOperation::CREATE_FROM_URI) {
724 LOGE("Invalid asset change request");
725 return false;
726 }
727
728 bool isMovingPhoto = IsMovingPhoto();
729 if (isMovingPhoto && !CheckMovingPhotoWriteOperation()) {
730 LOGE("Invalid write operation for moving photo");
731 return false;
732 }
733
734 return true;
735 }
736
SendFile(const UniqueFd & srcFd,const UniqueFd & destFd)737 static int32_t SendFile(const UniqueFd& srcFd, const UniqueFd& destFd)
738 {
739 if (srcFd.Get() < 0 || destFd.Get() < 0) {
740 LOGE("Failed to check srcFd: %{public}d and destFd: %{public}d", srcFd.Get(), destFd.Get());
741 return E_ERR;
742 }
743
744 struct stat statSrc {};
745 int32_t status = fstat(srcFd.Get(), &statSrc);
746 if (status != 0) {
747 LOGE("Failed to get file stat, errno=%{public}d", errno);
748 return status;
749 }
750
751 off_t offset = 0;
752 off_t fileSize = statSrc.st_size;
753 while (offset < fileSize) {
754 ssize_t sent = sendfile(destFd.Get(), srcFd.Get(), &offset, fileSize - offset);
755 if (sent < 0) {
756 LOGE("Failed to sendfile with errno=%{public}d, srcFd=%{private}d, destFd=%{private}d", errno, srcFd.Get(),
757 destFd.Get());
758 return sent;
759 }
760 }
761
762 return E_OK;
763 }
764
CopyFileToMediaLibrary(const UniqueFd & destFd,bool isMovingPhotoVideo)765 int32_t MediaAssetChangeRequestImpl::CopyFileToMediaLibrary(const UniqueFd& destFd, bool isMovingPhotoVideo)
766 {
767 std::string srcRealPath = isMovingPhotoVideo ? movingPhotoVideoRealPath_ : realPath_;
768 if (srcRealPath.empty()) {
769 LOGE("Failed to check real path of source");
770 return E_FAIL;
771 }
772
773 std::string absFilePath;
774 if (!PathToRealPath(srcRealPath, absFilePath)) {
775 LOGE("Not real path %{private}s", srcRealPath.c_str());
776 return E_FAIL;
777 }
778 UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
779 if (srcFd.Get() < 0) {
780 LOGE("Failed to open %{private}s, errno=%{public}d", absFilePath.c_str(), errno);
781 return srcFd.Get();
782 }
783
784 int32_t err = SendFile(srcFd, destFd);
785 if (err != E_OK) {
786 LOGE("Failed to send file from %{public}d to %{public}d", srcFd.Get(), destFd.Get());
787 }
788 return err;
789 }
790
CopyDataBufferToMediaLibrary(const UniqueFd & destFd,bool isMovingPhotoVideo)791 int32_t MediaAssetChangeRequestImpl::CopyDataBufferToMediaLibrary(const UniqueFd& destFd, bool isMovingPhotoVideo)
792 {
793 size_t offset = 0;
794 size_t length = isMovingPhotoVideo ? movingPhotoVideoBufferSize_ : dataBufferSize_;
795 void* dataBuffer = isMovingPhotoVideo ? movingPhotoVideoDataBuffer_ : dataBuffer_;
796 while (offset < length) {
797 ssize_t written = write(destFd.Get(), (char*)dataBuffer + offset, length - offset);
798 if (written < 0) {
799 LOGE("Failed to copy data buffer, return %{public}d", static_cast<int>(written));
800 return written;
801 }
802 offset += static_cast<size_t>(written);
803 }
804 return E_OK;
805 }
806
CopyMovingPhotoVideo(const std::string & assetUri)807 int32_t MediaAssetChangeRequestImpl::CopyMovingPhotoVideo(const std::string& assetUri)
808 {
809 if (assetUri.empty()) {
810 LOGE("Failed to check empty asset uri");
811 return E_INVALID_URI;
812 }
813
814 std::string videoUri = assetUri;
815 MediaFileUtils::UriAppendKeyValue(videoUri, MEDIA_MOVING_PHOTO_OPRN_KEYWORD, OPEN_MOVING_PHOTO_VIDEO);
816 Uri uri(videoUri);
817 int videoFd = UserFileClient::OpenFile(uri, MEDIA_FILEMODE_WRITEONLY);
818 if (videoFd < 0) {
819 LOGE("Failed to open video of moving photo with write-only mode");
820 return videoFd;
821 }
822
823 int32_t ret = E_ERR;
824 UniqueFd uniqueFd(videoFd);
825 if (movingPhotoVideoResourceMode_ == AddResourceMode::FILE_URI) {
826 ret = CopyFileToMediaLibrary(uniqueFd, true);
827 } else if (movingPhotoVideoResourceMode_ == AddResourceMode::DATA_BUFFER) {
828 ret = CopyDataBufferToMediaLibrary(uniqueFd, true);
829 } else {
830 LOGE("Invalid mode: %{public}d", movingPhotoVideoResourceMode_);
831 return E_INVALID_VALUES;
832 }
833 return ret;
834 }
835
SetNewFileAsset(int32_t id,const std::string & uri)836 void MediaAssetChangeRequestImpl::SetNewFileAsset(int32_t id, const std::string& uri)
837 {
838 if (fileAsset_ == nullptr) {
839 LOGE("fileAsset_ is nullptr");
840 return;
841 }
842
843 if (id <= 0 || uri.empty()) {
844 LOGE("Failed to check file_id: %{public}d and uri: %{public}s", id, uri.c_str());
845 return;
846 }
847 fileAsset_->SetId(id);
848 fileAsset_->SetUri(uri);
849 fileAsset_->SetTimePending(0);
850 }
851
CJSetTitle(std::string title)852 int32_t MediaAssetChangeRequestImpl::CJSetTitle(std::string title)
853 {
854 if (fileAsset_ == nullptr) {
855 return JS_INNER_FAIL;
856 }
857 std::string extension = MediaFileUtils::SplitByChar(fileAsset_->GetDisplayName(), '.');
858 std::string displayName = title + "." + extension;
859 if (MediaFileUtils::CheckDisplayName(displayName) != E_OK) {
860 return OHOS_INVALID_PARAM_CODE;
861 }
862 fileAsset_->SetTitle(title);
863 fileAsset_->SetDisplayName(displayName);
864 RecordChangeOperation(AssetChangeOperation::SET_TITLE);
865 if (Contains(AssetChangeOperation::CREATE_FROM_SCRATCH) || Contains(AssetChangeOperation::CREATE_FROM_URI)) {
866 creationValuesBucket_.valuesMap[MEDIA_DATA_DB_NAME] = displayName;
867 creationValuesBucket_.valuesMap[PhotoColumn::MEDIA_TITLE] = title;
868 }
869 return 0;
870 }
871
OpenWriteCacheHandler(MediaAssetChangeRequestImpl * changeRequest,bool isMovingPhotoVideo=false)872 static int32_t OpenWriteCacheHandler(MediaAssetChangeRequestImpl* changeRequest, bool isMovingPhotoVideo = false)
873 {
874 auto fileAsset = changeRequest->GetFileAssetInstance();
875 if (fileAsset == nullptr) {
876 return E_FAIL;
877 }
878 std::string extension = isMovingPhotoVideo ? MOVING_PHOTO_VIDEO_EXTENSION
879 : MediaFileUtils::GetExtensionFromPath(fileAsset->GetDisplayName());
880 int64_t currentTimestamp = MediaFileUtils::UTCTimeNanoSeconds();
881 uint32_t cacheFileId = changeRequest->FetchAddCacheFileId();
882 std::string cacheFileName = std::to_string(currentTimestamp) + "_" + std::to_string(cacheFileId) + "." + extension;
883 std::string uri = PhotoColumn::PHOTO_CACHE_URI_PREFIX + cacheFileName;
884 MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
885 Uri openCacheUri(uri);
886 int32_t ret = UserFileClient::OpenFile(openCacheUri, MEDIA_FILEMODE_WRITEONLY);
887 if (ret == E_PERMISSION_DENIED) {
888 LOGE("Open cache file failed, permission denied");
889 return OHOS_PERMISSION_DENIED_CODE;
890 }
891 if (ret < 0) {
892 LOGE("Open cache file failed, ret: %{public}d", ret);
893 }
894
895 if (isMovingPhotoVideo) {
896 changeRequest->SetCacheMovingPhotoVideoName(cacheFileName);
897 } else {
898 changeRequest->SetCacheFileName(cacheFileName);
899 }
900 return ret;
901 }
902
CJGetWriteCacheHandler(int32_t * errCode)903 int32_t MediaAssetChangeRequestImpl::CJGetWriteCacheHandler(int32_t* errCode)
904 {
905 if (fileAsset_ == nullptr) {
906 *errCode = JS_INNER_FAIL;
907 return 0;
908 }
909 if (IsMovingPhoto()) {
910 *errCode = JS_E_OPERATION_NOT_SUPPORT;
911 return 0;
912 }
913 if (Contains(AssetChangeOperation::CREATE_FROM_URI) || Contains(AssetChangeOperation::GET_WRITE_CACHE_HANDLER) ||
914 Contains(AssetChangeOperation::ADD_RESOURCE)) {
915 *errCode = JS_E_OPERATION_NOT_SUPPORT;
916 return 0;
917 }
918 int32_t ret = OpenWriteCacheHandler(this);
919 if (ret < 0) {
920 LOGE("Failed to open write cache handler, ret: %{public}d", ret);
921 *errCode = ret;
922 return 0;
923 }
924 RecordChangeOperation(AssetChangeOperation::GET_WRITE_CACHE_HANDLER);
925 return ret;
926 }
927
CheckWriteOperation(MediaAssetChangeRequestImpl * changeRequest,ResourceType resourceType=ResourceType::INVALID_RESOURCE)928 static int32_t CheckWriteOperation(
929 MediaAssetChangeRequestImpl* changeRequest, ResourceType resourceType = ResourceType::INVALID_RESOURCE)
930 {
931 if (changeRequest == nullptr) {
932 LOGE("changeRequest is null");
933 return OHOS_INVALID_PARAM_CODE;
934 }
935
936 if (changeRequest->IsMovingPhoto()) {
937 if (!changeRequest->CheckMovingPhotoResource(resourceType)) {
938 LOGE("Failed to check resource to add for moving photo");
939 return OHOS_INVALID_PARAM_CODE;
940 }
941 return 0;
942 }
943
944 if (changeRequest->Contains(AssetChangeOperation::CREATE_FROM_URI) ||
945 changeRequest->Contains(AssetChangeOperation::GET_WRITE_CACHE_HANDLER) ||
946 changeRequest->Contains(AssetChangeOperation::ADD_RESOURCE)) {
947 LOGE("The previous asset creation/modification request has not been applied");
948 return JS_E_OPERATION_NOT_SUPPORT;
949 }
950 return 0;
951 }
952
GetResourceType(int32_t value)953 static ResourceType GetResourceType(int32_t value)
954 {
955 ResourceType result = ResourceType::INVALID_RESOURCE;
956 switch (value) {
957 case static_cast<int32_t>(ResourceType::IMAGE_RESOURCE):
958 case static_cast<int32_t>(ResourceType::VIDEO_RESOURCE):
959 case static_cast<int32_t>(ResourceType::PHOTO_PROXY):
960 result = static_cast<ResourceType>(value);
961 break;
962 default:
963 break;
964 }
965 return result;
966 }
967
CheckMovingPhotoVideo(void * dataBuffer,size_t size)968 static bool CheckMovingPhotoVideo(void* dataBuffer, size_t size)
969 {
970 auto dataSource = std::make_shared<MediaDataSource>(dataBuffer, static_cast<int64_t>(size));
971 auto avMetadataHelper = AVMetadataHelperFactory::CreateAVMetadataHelper();
972 if (avMetadataHelper == nullptr) {
973 LOGE("Failed to create AVMetadataHelper, ignore checking duration of moving photo video");
974 return true;
975 }
976
977 int32_t err = avMetadataHelper->SetSource(dataSource);
978 if (err != E_OK) {
979 LOGE("SetSource failed for dataSource, err = %{public}d", err);
980 return false;
981 }
982
983 std::unordered_map<int32_t, std::string> resultMap = avMetadataHelper->ResolveMetadata();
984 if (resultMap.find(AV_KEY_DURATION) == resultMap.end()) {
985 LOGE("AV_KEY_DURATION does not exist");
986 return false;
987 }
988
989 std::string durationStr = resultMap.at(AV_KEY_DURATION);
990 int32_t duration = std::atoi(durationStr.c_str());
991 if (!MediaFileUtils::CheckMovingPhotoVideoDuration(duration)) {
992 LOGE("Failed to check duration of moving photo video: %{public}d ms", duration);
993 return false;
994 }
995 return true;
996 }
997
AddMovingPhotoVideoResource(std::string fileUri)998 int32_t MediaAssetChangeRequestImpl::AddMovingPhotoVideoResource(std::string fileUri)
999 {
1000 std::string realPath;
1001 if (!ParseFileUri(fileUri, MediaType::MEDIA_TYPE_VIDEO, realPath)) {
1002 return OHOS_INVALID_PARAM_CODE;
1003 }
1004 if (!MediaFileUtils::CheckMovingPhotoVideo(realPath)) {
1005 LOGE("Failed to check video resource of moving photo");
1006 return OHOS_INVALID_PARAM_CODE;
1007 }
1008 movingPhotoVideoRealPath_ = realPath;
1009 movingPhotoVideoResourceMode_ = AddResourceMode::FILE_URI;
1010 RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
1011 addResourceTypes_.push_back(ResourceType::VIDEO_RESOURCE);
1012 return 0;
1013 }
1014
AddMovingPhotoVideoResource(uint8_t * dataBuffer,size_t dataBufferSize)1015 int32_t MediaAssetChangeRequestImpl::AddMovingPhotoVideoResource(uint8_t* dataBuffer, size_t dataBufferSize)
1016 {
1017 movingPhotoVideoDataBuffer_ = dataBuffer;
1018 movingPhotoVideoBufferSize_ = dataBufferSize;
1019 if (!CheckMovingPhotoVideo(movingPhotoVideoDataBuffer_, movingPhotoVideoBufferSize_)) {
1020 LOGE("Failed to check video resource of moving photo");
1021 return OHOS_INVALID_PARAM_CODE;
1022 }
1023 movingPhotoVideoResourceMode_ = AddResourceMode::DATA_BUFFER;
1024 RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
1025 addResourceTypes_.push_back(ResourceType::VIDEO_RESOURCE);
1026 return 0;
1027 }
1028
CJAddResource(int32_t resourceType,std::string fileUri)1029 int32_t MediaAssetChangeRequestImpl::CJAddResource(int32_t resourceType, std::string fileUri)
1030 {
1031 if (fileAsset_ == nullptr) {
1032 return JS_INNER_FAIL;
1033 }
1034 if (CheckWriteOperation(this, GetResourceType(resourceType)) != E_OK) {
1035 return JS_E_OPERATION_NOT_SUPPORT;
1036 }
1037 if (IsMovingPhoto() && resourceType == static_cast<int32_t>(ResourceType::VIDEO_RESOURCE)) {
1038 return AddMovingPhotoVideoResource(fileUri);
1039 }
1040 if (!(resourceType == static_cast<int32_t>(fileAsset_->GetMediaType()) ||
1041 resourceType == static_cast<int32_t>(ResourceType::PHOTO_PROXY))) {
1042 LOGE("Failed to check resourceType");
1043 return OHOS_INVALID_PARAM_CODE;
1044 }
1045 std::string realPath;
1046 if (!ParseFileUri(fileUri, fileAsset_->GetMediaType(), realPath)) {
1047 return OHOS_INVALID_PARAM_CODE;
1048 }
1049 realPath_ = realPath;
1050 addResourceMode_ = AddResourceMode::FILE_URI;
1051 RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
1052 addResourceTypes_.push_back(GetResourceType(resourceType));
1053 return 0;
1054 }
1055
CJAddResource(int32_t resourceType,uint8_t * dataBuffer,size_t dataBufferSize)1056 int32_t MediaAssetChangeRequestImpl::CJAddResource(int32_t resourceType, uint8_t* dataBuffer, size_t dataBufferSize)
1057 {
1058 if (dataBufferSize <= 0) {
1059 LOGE("Failed to check size of data buffer");
1060 return OHOS_INVALID_PARAM_CODE;
1061 }
1062 if (fileAsset_ == nullptr) {
1063 return JS_INNER_FAIL;
1064 }
1065 if (CheckWriteOperation(this, GetResourceType(resourceType)) != E_OK) {
1066 return JS_E_OPERATION_NOT_SUPPORT;
1067 }
1068 if (IsMovingPhoto() && resourceType == static_cast<int32_t>(ResourceType::VIDEO_RESOURCE)) {
1069 return AddMovingPhotoVideoResource(dataBuffer, dataBufferSize);
1070 }
1071 if (!(resourceType == static_cast<int32_t>(fileAsset_->GetMediaType()) ||
1072 resourceType == static_cast<int32_t>(ResourceType::PHOTO_PROXY))) {
1073 LOGE("Failed to check resourceType");
1074 return OHOS_INVALID_PARAM_CODE;
1075 }
1076 dataBuffer_ = dataBuffer;
1077 dataBufferSize_ = dataBufferSize;
1078 addResourceMode_ = AddResourceMode::DATA_BUFFER;
1079 RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
1080 addResourceTypes_.push_back(GetResourceType(resourceType));
1081 return 0;
1082 }
1083
CJSaveCameraPhoto()1084 int32_t MediaAssetChangeRequestImpl::CJSaveCameraPhoto()
1085 {
1086 if (fileAsset_ == nullptr) {
1087 return JS_INNER_FAIL;
1088 }
1089 if (Contains(AssetChangeOperation::SET_EDIT_DATA) && !Contains(AssetChangeOperation::ADD_FILTERS)) {
1090 RecordChangeOperation(AssetChangeOperation::ADD_FILTERS);
1091 }
1092 RecordChangeOperation(AssetChangeOperation::SAVE_CAMERA_PHOTO);
1093 return 0;
1094 }
1095
CJDiscardCameraPhoto()1096 int32_t MediaAssetChangeRequestImpl::CJDiscardCameraPhoto()
1097 {
1098 if (fileAsset_ == nullptr) {
1099 return JS_INNER_FAIL;
1100 }
1101 RecordChangeOperation(AssetChangeOperation::DISCARD_CAMERA_PHOTO);
1102 return 0;
1103 }
1104
CJSetOrientation(int32_t orientation)1105 int32_t MediaAssetChangeRequestImpl::CJSetOrientation(int32_t orientation)
1106 {
1107 if (fileAsset_ == nullptr) {
1108 return OHOS_INVALID_PARAM_CODE;
1109 }
1110 if (std::find(ORIENTATION_ARRAY.begin(), ORIENTATION_ARRAY.end(), orientation) == ORIENTATION_ARRAY.end()) {
1111 LOGE("orientationValue value is invalid.");
1112 return OHOS_INVALID_PARAM_CODE;
1113 }
1114 fileAsset_->SetOrientation(orientation);
1115 RecordChangeOperation(AssetChangeOperation::SET_ORIENTATION);
1116 return 0;
1117 }
1118
IsCreation(MediaAssetChangeRequestImpl * changeRequest)1119 static bool IsCreation(MediaAssetChangeRequestImpl* changeRequest)
1120 {
1121 auto assetChangeOperations = changeRequest->GetAssetChangeOperations();
1122 bool isCreateFromScratch = std::find(assetChangeOperations.begin(), assetChangeOperations.end(),
1123 AssetChangeOperation::CREATE_FROM_SCRATCH) != assetChangeOperations.end();
1124 bool isCreateFromUri = std::find(assetChangeOperations.begin(), assetChangeOperations.end(),
1125 AssetChangeOperation::CREATE_FROM_URI) != assetChangeOperations.end();
1126 return isCreateFromScratch || isCreateFromUri;
1127 }
1128
IsSetEffectMode(MediaAssetChangeRequestImpl * changeRequest)1129 static bool IsSetEffectMode(MediaAssetChangeRequestImpl* changeRequest)
1130 {
1131 auto assetChangeOperations = changeRequest->GetAssetChangeOperations();
1132 return std::find(assetChangeOperations.begin(), assetChangeOperations.end(),
1133 AssetChangeOperation::SET_MOVING_PHOTO_EFFECT_MODE) != assetChangeOperations.end();
1134 }
1135
WriteBySecurityComponent(MediaAssetChangeRequestImpl * changeRequest)1136 static bool WriteBySecurityComponent(MediaAssetChangeRequestImpl* changeRequest)
1137 {
1138 bool isCreation = IsCreation(changeRequest);
1139 int32_t ret = E_FAIL;
1140 auto assetChangeOperations = changeRequest->GetAssetChangeOperations();
1141 bool isCreateFromUri = std::find(assetChangeOperations.begin(), assetChangeOperations.end(),
1142 AssetChangeOperation::CREATE_FROM_URI) != assetChangeOperations.end();
1143 if (isCreateFromUri) {
1144 ret = changeRequest->CopyToMediaLibrary(isCreation, AddResourceMode::FILE_URI);
1145 } else {
1146 ret = changeRequest->CopyToMediaLibrary(isCreation, changeRequest->GetAddResourceMode());
1147 }
1148
1149 if (ret < 0) {
1150 LOGE("Failed to write by security component, ret: %{public}d", ret);
1151 return false;
1152 }
1153 return true;
1154 }
1155
SendToCacheFile(MediaAssetChangeRequestImpl * changeRequest,const UniqueFd & destFd,bool isMovingPhotoVideo=false)1156 static bool SendToCacheFile(
1157 MediaAssetChangeRequestImpl* changeRequest, const UniqueFd& destFd, bool isMovingPhotoVideo = false)
1158 {
1159 std::string realPath =
1160 isMovingPhotoVideo ? changeRequest->GetMovingPhotoVideoPath() : changeRequest->GetFileRealPath();
1161
1162 std::string absFilePath;
1163 if (!PathToRealPath(realPath, absFilePath)) {
1164 LOGE("Not real path %{private}s, errno=%{public}d", realPath.c_str(), errno);
1165 return false;
1166 }
1167
1168 UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
1169 if (srcFd.Get() < 0) {
1170 LOGE("Failed to open file, errno=%{public}d", errno);
1171 return false;
1172 }
1173
1174 int32_t err = SendFile(srcFd, destFd);
1175 if (err != E_OK) {
1176 LOGE("Failed to send file from %{public}d to %{public}d", srcFd.Get(), destFd.Get());
1177 return false;
1178 }
1179 return true;
1180 }
1181
SubmitCache(bool isCreation,bool isSetEffectMode)1182 int32_t MediaAssetChangeRequestImpl::SubmitCache(bool isCreation, bool isSetEffectMode)
1183 {
1184 if (fileAsset_ == nullptr) {
1185 return E_FAIL;
1186 }
1187 if (cacheFileName_.empty() && cacheMovingPhotoVideoName_.empty()) {
1188 LOGE("Failed to check cache file");
1189 return E_FAIL;
1190 }
1191 std::string uri = PAH_SUBMIT_CACHE;
1192 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1193 Uri submitCacheUri(uri);
1194 std::string assetUri;
1195 int32_t ret;
1196 if (isCreation) {
1197 bool isValid = false;
1198 std::string displayName = creationValuesBucket_.Get(MEDIA_DATA_DB_NAME, isValid);
1199 if (!isValid || MediaFileUtils::CheckDisplayName(displayName) != E_OK) {
1200 LOGE("Failed to check displayName");
1201 return E_FAIL;
1202 }
1203 creationValuesBucket_.Put(CACHE_FILE_NAME, cacheFileName_);
1204 if (IsMovingPhoto()) {
1205 creationValuesBucket_.Put(CACHE_MOVING_PHOTO_VIDEO_NAME, cacheMovingPhotoVideoName_);
1206 }
1207 ret = UserFileClient::InsertExt(submitCacheUri, creationValuesBucket_, assetUri);
1208 } else {
1209 DataShare::DataShareValuesBucket valuesBucket;
1210 valuesBucket.Put(PhotoColumn::MEDIA_ID, fileAsset_->GetId());
1211 valuesBucket.Put(CACHE_FILE_NAME, cacheFileName_);
1212 ret = PutMediaAssetEditData(valuesBucket);
1213 if (ret != E_OK) {
1214 LOGE("Failed to put editData");
1215 return E_FAIL;
1216 }
1217 if (IsMovingPhoto()) {
1218 valuesBucket.Put(CACHE_MOVING_PHOTO_VIDEO_NAME, cacheMovingPhotoVideoName_);
1219 }
1220 if (isSetEffectMode) {
1221 valuesBucket.Put(PhotoColumn::MOVING_PHOTO_EFFECT_MODE, fileAsset_->GetMovingPhotoEffectMode());
1222 valuesBucket.Put(CACHE_MOVING_PHOTO_VIDEO_NAME, cacheMovingPhotoVideoName_);
1223 }
1224 ret = UserFileClient::Insert(submitCacheUri, valuesBucket);
1225 }
1226 if (ret > 0 && isCreation) {
1227 SetNewFileAsset(ret, assetUri);
1228 }
1229 cacheFileName_.clear();
1230 cacheMovingPhotoVideoName_.clear();
1231 return ret;
1232 }
1233
SubmitCacheExecute(MediaAssetChangeRequestImpl * changeRequest)1234 static bool SubmitCacheExecute(MediaAssetChangeRequestImpl* changeRequest)
1235 {
1236 bool isCreation = IsCreation(changeRequest);
1237 bool isSetEffectMode = IsSetEffectMode(changeRequest);
1238 int32_t ret = changeRequest->SubmitCache(isCreation, isSetEffectMode);
1239 if (ret < 0) {
1240 LOGE("Failed to write cache, ret: %{public}d", ret);
1241 return false;
1242 }
1243 return true;
1244 }
1245
CreateFromFileUriExecute(MediaAssetChangeRequestImpl * changeRequest)1246 static bool CreateFromFileUriExecute(MediaAssetChangeRequestImpl* changeRequest)
1247 {
1248 if (!HasWritePermission()) {
1249 return WriteBySecurityComponent(changeRequest);
1250 }
1251
1252 int32_t cacheFd = OpenWriteCacheHandler(changeRequest);
1253 if (cacheFd < 0) {
1254 LOGE("Failed to open write cache handler, err: %{public}d", cacheFd);
1255 return false;
1256 }
1257
1258 UniqueFd uniqueFd(cacheFd);
1259 if (!SendToCacheFile(changeRequest, uniqueFd)) {
1260 LOGE("Faild to write cache file");
1261 return false;
1262 }
1263 return SubmitCacheExecute(changeRequest);
1264 }
1265
HasAddResource(std::vector<ResourceType> addResourceTypes,ResourceType resourceType)1266 static bool HasAddResource(std::vector<ResourceType> addResourceTypes, ResourceType resourceType)
1267 {
1268 return std::find(addResourceTypes.begin(), addResourceTypes.end(), resourceType) != addResourceTypes.end();
1269 }
1270
WriteCacheByArrayBuffer(MediaAssetChangeRequestImpl * changeRequest,const UniqueFd & destFd,bool isMovingPhotoVideo=false)1271 static bool WriteCacheByArrayBuffer(
1272 MediaAssetChangeRequestImpl* changeRequest, const UniqueFd& destFd, bool isMovingPhotoVideo = false)
1273 {
1274 size_t offset = 0;
1275 size_t length = isMovingPhotoVideo ? changeRequest->GetMovingPhotoVideoSize() : changeRequest->GetDataBufferSize();
1276 void* dataBuffer = isMovingPhotoVideo ? changeRequest->GetMovingPhotoVideoBuffer() : changeRequest->GetDataBuffer();
1277 while (offset < length) {
1278 ssize_t written = write(destFd.Get(), (char*)dataBuffer + offset, length - offset);
1279 if (written < 0) {
1280 LOGE("Failed to write data buffer to cache file, return %{public}d", static_cast<int>(written));
1281 return false;
1282 }
1283 offset += static_cast<size_t>(written);
1284 }
1285 return true;
1286 }
1287
SavePhotoProxyImage(const UniqueFd & destFd,sptr<PhotoProxy> photoProxyPtr)1288 static int SavePhotoProxyImage(const UniqueFd& destFd, sptr<PhotoProxy> photoProxyPtr)
1289 {
1290 void* imageAddr = photoProxyPtr->GetFileDataAddr();
1291 size_t imageSize = photoProxyPtr->GetFileSize();
1292 if (imageAddr == nullptr || imageSize == 0) {
1293 LOGE("imageAddr is nullptr or imageSize(%{public}zu)==0", imageSize);
1294 return E_ERR;
1295 }
1296
1297 NAPI_INFO_LOG("start pack PixelMap");
1298 Media::InitializationOptions opts;
1299 opts.pixelFormat = Media::PixelFormat::RGBA_8888;
1300 opts.size = { .width = photoProxyPtr->GetWidth(), .height = photoProxyPtr->GetHeight() };
1301 auto pixelMap = Media::PixelMap::Create(opts);
1302 if (pixelMap == nullptr) {
1303 LOGE("Create pixelMap failed.");
1304 return E_ERR;
1305 }
1306 pixelMap->SetPixelsAddr(imageAddr, nullptr, imageSize, Media::AllocatorType::SHARE_MEM_ALLOC, nullptr);
1307 auto pixelSize = static_cast<uint32_t>(pixelMap->GetByteCount());
1308
1309 // encode rgba to jpeg
1310 auto buffer = new (std::nothrow) uint8_t[pixelSize];
1311 int64_t packedSize = 0L;
1312 Media::ImagePacker imagePacker;
1313 Media::PackOption packOption;
1314 packOption.format = "image/jpeg";
1315 imagePacker.StartPacking(buffer, pixelSize, packOption);
1316 imagePacker.AddImage(*pixelMap);
1317 imagePacker.FinalizePacking(packedSize);
1318 if (buffer == nullptr) {
1319 LOGE("packet pixelMap failed");
1320 return E_ERR;
1321 }
1322 NAPI_INFO_LOG("pack pixelMap success, packedSize: %{public}" PRId64, packedSize);
1323
1324 int ret = write(destFd, buffer, packedSize);
1325 if (ret < 0) {
1326 LOGE("Failed to write photo proxy to cache file, return %{public}d", ret);
1327 delete[] buffer;
1328 return ret;
1329 }
1330 delete[] buffer;
1331 return ret;
1332 }
1333
AddPhotoProxyResourceExecute(MediaAssetChangeRequestImpl * changeRequest,const UniqueFd & destFd)1334 static bool AddPhotoProxyResourceExecute(MediaAssetChangeRequestImpl* changeRequest, const UniqueFd& destFd)
1335 {
1336 std::string uri = PAH_ADD_IMAGE;
1337 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1338 Uri updateAssetUri(uri);
1339
1340 auto fileAsset = changeRequest->GetFileAssetInstance();
1341 DataShare::DataSharePredicates predicates;
1342 predicates.SetWhereClause(PhotoColumn::MEDIA_ID + " = ? ");
1343 predicates.SetWhereArgs({ std::to_string(fileAsset->GetId()) });
1344
1345 DataShare::DataShareValuesBucket valuesBucket;
1346 valuesBucket.Put(PhotoColumn::PHOTO_ID, changeRequest->GetPhotoProxyObj()->GetPhotoId());
1347 NAPI_INFO_LOG("photoId: %{public}s", changeRequest->GetPhotoProxyObj()->GetPhotoId().c_str());
1348 valuesBucket.Put(PhotoColumn::PHOTO_DEFERRED_PROC_TYPE,
1349 static_cast<int32_t>(changeRequest->GetPhotoProxyObj()->GetDeferredProcType()));
1350 valuesBucket.Put(MediaColumn::MEDIA_ID, fileAsset->GetId());
1351 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
1352 if (changedRows < 0) {
1353 LOGE("Failed to set, err: %{public}d", changedRows);
1354 return false;
1355 }
1356
1357 int err = SavePhotoProxyImage(destFd, changeRequest->GetPhotoProxyObj());
1358 changeRequest->ReleasePhotoProxyObj();
1359 if (err < 0) {
1360 LOGE("Failed to saveImage , err: %{public}d", err);
1361 return false;
1362 }
1363 return true;
1364 }
1365
AddResourceByMode(MediaAssetChangeRequestImpl * changeRequest,const UniqueFd & uniqueFd,AddResourceMode mode,bool isMovingPhotoVideo=false)1366 static bool AddResourceByMode(MediaAssetChangeRequestImpl* changeRequest, const UniqueFd& uniqueFd,
1367 AddResourceMode mode, bool isMovingPhotoVideo = false)
1368 {
1369 bool isWriteSuccess = false;
1370 if (mode == AddResourceMode::DATA_BUFFER) {
1371 isWriteSuccess = WriteCacheByArrayBuffer(changeRequest, uniqueFd, isMovingPhotoVideo);
1372 } else if (mode == AddResourceMode::FILE_URI) {
1373 isWriteSuccess = SendToCacheFile(changeRequest, uniqueFd, isMovingPhotoVideo);
1374 } else if (mode == AddResourceMode::PHOTO_PROXY) {
1375 isWriteSuccess = AddPhotoProxyResourceExecute(changeRequest, uniqueFd);
1376 } else {
1377 LOGE("Unsupported addResource mode");
1378 }
1379 return isWriteSuccess;
1380 }
1381
AddMovingPhotoVideoExecute(MediaAssetChangeRequestImpl * changeRequest)1382 static bool AddMovingPhotoVideoExecute(MediaAssetChangeRequestImpl* changeRequest)
1383 {
1384 int32_t cacheVideoFd = OpenWriteCacheHandler(changeRequest, true);
1385 if (cacheVideoFd < 0) {
1386 LOGE("Failed to open cache moving photo video, err: %{public}d", cacheVideoFd);
1387 return false;
1388 }
1389
1390 UniqueFd uniqueFd(cacheVideoFd);
1391 AddResourceMode mode = changeRequest->GetMovingPhotoVideoMode();
1392 if (!AddResourceByMode(changeRequest, uniqueFd, mode, true)) {
1393 LOGE("Faild to write cache file");
1394 return false;
1395 }
1396 return true;
1397 }
1398
AddResourceExecute(MediaAssetChangeRequestImpl * changeRequest)1399 static bool AddResourceExecute(MediaAssetChangeRequestImpl* changeRequest)
1400 {
1401 if (!HasWritePermission()) {
1402 return WriteBySecurityComponent(changeRequest);
1403 }
1404
1405 if (changeRequest->IsMovingPhoto() &&
1406 HasAddResource(changeRequest->GetAddResourceTypes(), ResourceType::VIDEO_RESOURCE) &&
1407 !AddMovingPhotoVideoExecute(changeRequest)) {
1408 LOGE("Faild to write cache file for video of moving photo");
1409 return false;
1410 }
1411
1412 // image resource is not mandatory when setting effect mode of moving photo
1413 if (changeRequest->IsMovingPhoto() &&
1414 !HasAddResource(changeRequest->GetAddResourceTypes(), ResourceType::IMAGE_RESOURCE)) {
1415 return SubmitCacheExecute(changeRequest);
1416 }
1417
1418 int32_t cacheFd = OpenWriteCacheHandler(changeRequest);
1419 if (cacheFd < 0) {
1420 LOGE("Failed to open write cache handler, err: %{public}d", cacheFd);
1421 return false;
1422 }
1423
1424 UniqueFd uniqueFd(cacheFd);
1425 AddResourceMode mode = changeRequest->GetAddResourceMode();
1426 if (!AddResourceByMode(changeRequest, uniqueFd, mode)) {
1427 LOGE("Faild to write cache file");
1428 return false;
1429 }
1430 return SubmitCacheExecute(changeRequest);
1431 }
1432
UpdateAssetProperty(MediaAssetChangeRequestImpl * changeRequest,std::string uri,DataShare::DataSharePredicates & predicates,DataShare::DataShareValuesBucket & valuesBucket)1433 static bool UpdateAssetProperty(MediaAssetChangeRequestImpl* changeRequest, std::string uri,
1434 DataShare::DataSharePredicates& predicates, DataShare::DataShareValuesBucket& valuesBucket)
1435 {
1436 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1437 Uri updateAssetUri(uri);
1438 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
1439 if (changedRows < 0) {
1440 LOGE("Failed to update property of asset, err: %{public}d", changedRows);
1441 return false;
1442 }
1443 return true;
1444 }
1445
SetTitleExecute(MediaAssetChangeRequestImpl * changeRequest)1446 static bool SetTitleExecute(MediaAssetChangeRequestImpl* changeRequest)
1447 {
1448 // In the scenario of creation, the new title will be applied when the asset is created.
1449 AssetChangeOperation firstOperation = changeRequest->GetAssetChangeOperations().front();
1450 if (firstOperation == AssetChangeOperation::CREATE_FROM_SCRATCH ||
1451 firstOperation == AssetChangeOperation::CREATE_FROM_URI) {
1452 return true;
1453 }
1454
1455 DataShare::DataSharePredicates predicates;
1456 DataShare::DataShareValuesBucket valuesBucket;
1457 auto fileAsset = changeRequest->GetFileAssetInstance();
1458 predicates.EqualTo(PhotoColumn::MEDIA_ID, std::to_string(fileAsset->GetId()));
1459 valuesBucket.Put(PhotoColumn::MEDIA_TITLE, fileAsset->GetTitle());
1460 return UpdateAssetProperty(changeRequest, PAH_UPDATE_PHOTO, predicates, valuesBucket);
1461 }
1462
DiscardHighQualityPhoto(MediaAssetChangeRequestImpl * changeRequest)1463 static void DiscardHighQualityPhoto(MediaAssetChangeRequestImpl* changeRequest)
1464 {
1465 std::string uriStr = PAH_REMOVE_MSC_TASK;
1466 MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1467 Uri uri(uriStr);
1468 DataShare::DataSharePredicates predicates;
1469 int errCode = 0;
1470 auto fileAsset = changeRequest->GetFileAssetInstance();
1471 std::vector<std::string> columns { std::to_string(fileAsset->GetId()) };
1472 UserFileClient::Query(uri, predicates, columns, errCode);
1473 }
1474
SaveCameraPhotoExecute(MediaAssetChangeRequestImpl * changeRequest)1475 static bool SaveCameraPhotoExecute(MediaAssetChangeRequestImpl* changeRequest)
1476 {
1477 auto changeOpreations = changeRequest->GetAssetChangeOperations();
1478 bool containsAddResource = std::find(changeOpreations.begin(), changeOpreations.end(),
1479 AssetChangeOperation::ADD_RESOURCE) != changeOpreations.end();
1480 if (containsAddResource && !MediaLibraryNapiUtils::IsSystemApp()) {
1481 // remove high quality photo
1482 LOGI("discard high quality photo because add resource by third app");
1483 DiscardHighQualityPhoto(changeRequest);
1484 }
1485
1486 // The watermark will trigger the scan. If the watermark is turned on, there is no need to trigger the scan again.
1487 bool needScan = std::find(changeOpreations.begin(), changeOpreations.end(),
1488 AssetChangeOperation::ADD_FILTERS) == changeOpreations.end();
1489
1490 auto fileAsset = changeRequest->GetFileAssetInstance();
1491 if (fileAsset == nullptr) {
1492 LOGE("fileAsset is nullptr");
1493 return false;
1494 }
1495 std::string uriStr = PAH_SAVE_CAMERA_PHOTO;
1496 MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1497 MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, MEDIA_OPERN_KEYWORD, std::to_string(needScan));
1498 MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_FILE_PATH, fileAsset->GetUri());
1499 MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_ID, std::to_string(fileAsset->GetId()));
1500 MediaLibraryNapiUtils::UriAppendKeyValue(
1501 uriStr, PhotoColumn::PHOTO_SUBTYPE, std::to_string(fileAsset->GetPhotoSubType()));
1502 MediaLibraryNapiUtils::UriAppendKeyValue(
1503 uriStr, IMAGE_FILE_TYPE, std::to_string(changeRequest->GetImageFileType()));
1504 Uri uri(uriStr);
1505 DataShare::DataShareValuesBucket valuesBucket;
1506 valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, false);
1507 DataShare::DataSharePredicates predicates;
1508 auto ret = UserFileClient::Update(uri, predicates, valuesBucket);
1509 if (ret < 0) {
1510 LOGE("save camera photo fail");
1511 }
1512 return true;
1513 }
1514
AddFiltersExecute(MediaAssetChangeRequestImpl * changeRequest)1515 static bool AddFiltersExecute(MediaAssetChangeRequestImpl* changeRequest)
1516 {
1517 auto fileAsset = changeRequest->GetFileAssetInstance();
1518 if (fileAsset == nullptr) {
1519 LOGE("Failed to check fileAsset");
1520 return false;
1521 }
1522 std::string uri = PAH_ADD_FILTERS;
1523 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1524 Uri addFiltersUri(uri);
1525
1526 DataShare::DataShareValuesBucket valuesBucket;
1527 valuesBucket.Put(PhotoColumn::MEDIA_ID, fileAsset->GetId());
1528 int ret = changeRequest->PutMediaAssetEditData(valuesBucket);
1529 if (ret != E_OK) {
1530 LOGE("Failed to put editData");
1531 return false;
1532 }
1533 ret = UserFileClient::Insert(addFiltersUri, valuesBucket);
1534 if (ret < 0) {
1535 LOGE("Failed to add filters, ret: %{public}d", ret);
1536 return false;
1537 }
1538 return true;
1539 }
1540
DiscardCameraPhotoExecute(MediaAssetChangeRequestImpl * changeRequest)1541 static bool DiscardCameraPhotoExecute(MediaAssetChangeRequestImpl* changeRequest)
1542 {
1543 DataShare::DataSharePredicates predicates;
1544 DataShare::DataShareValuesBucket valuesBucket;
1545 valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, true);
1546 auto fileAsset = changeRequest->GetFileAssetInstance();
1547 predicates.EqualTo(PhotoColumn::MEDIA_ID, std::to_string(fileAsset->GetId()));
1548 predicates.EqualTo(PhotoColumn::PHOTO_IS_TEMP, "1"); // only temp camera photo can be discarded
1549
1550 std::string uri = PAH_DISCARD_CAMERA_PHOTO;
1551 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1552 Uri updateAssetUri(uri);
1553 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
1554 if (changedRows < 0) {
1555 LOGE("Failed to update property of asset, err: %{public}d", changedRows);
1556 return false;
1557 }
1558 return true;
1559 }
1560
SetOrientationExecute(MediaAssetChangeRequestImpl * changeRequest)1561 static bool SetOrientationExecute(MediaAssetChangeRequestImpl* changeRequest)
1562 {
1563 DataShare::DataSharePredicates predicates;
1564 DataShare::DataShareValuesBucket valuesBucket;
1565 auto fileAsset = changeRequest->GetFileAssetInstance();
1566 if (fileAsset == nullptr) {
1567 LOGE("fileAsset is null");
1568 return false;
1569 }
1570 predicates.EqualTo(PhotoColumn::MEDIA_ID, std::to_string(fileAsset->GetId()));
1571 valuesBucket.Put(PhotoColumn::PHOTO_ORIENTATION, fileAsset->GetOrientation());
1572 return UpdateAssetProperty(changeRequest, PAH_UPDATE_PHOTO, predicates, valuesBucket);
1573 }
1574
1575 static const std::unordered_map<AssetChangeOperation, bool (*)(MediaAssetChangeRequestImpl*)> EXECUTE_MAP = {
1576 { AssetChangeOperation::CREATE_FROM_URI, CreateFromFileUriExecute },
1577 { AssetChangeOperation::GET_WRITE_CACHE_HANDLER, SubmitCacheExecute },
1578 { AssetChangeOperation::ADD_RESOURCE, AddResourceExecute },
1579 { AssetChangeOperation::SET_TITLE, SetTitleExecute },
1580 { AssetChangeOperation::SET_ORIENTATION, SetOrientationExecute },
1581 { AssetChangeOperation::SAVE_CAMERA_PHOTO, SaveCameraPhotoExecute },
1582 { AssetChangeOperation::ADD_FILTERS, AddFiltersExecute },
1583 { AssetChangeOperation::DISCARD_CAMERA_PHOTO, DiscardCameraPhotoExecute },
1584 };
1585
ApplyChanges()1586 int32_t MediaAssetChangeRequestImpl::ApplyChanges()
1587 {
1588 if (!CheckChangeOperations()) {
1589 LOGE("Failed to check asset change request operations");
1590 return OHOS_INVALID_PARAM_CODE;
1591 }
1592 std::unordered_set<AssetChangeOperation> appliedOperations;
1593 for (const auto& changeOperation : assetChangeOperations_) {
1594 // Keep the final result of each operation, and commit it only once.
1595 if (appliedOperations.find(changeOperation) != appliedOperations.end()) {
1596 continue;
1597 }
1598
1599 bool valid = false;
1600 auto iter = EXECUTE_MAP.find(changeOperation);
1601 if (iter != EXECUTE_MAP.end()) {
1602 valid = iter->second(this);
1603 } else if (changeOperation == AssetChangeOperation::CREATE_FROM_SCRATCH ||
1604 changeOperation == AssetChangeOperation::SET_EDIT_DATA) {
1605 // Perform CREATE_FROM_SCRATCH and SET_EDIT_DATA during GET_WRITE_CACHE_HANDLER or ADD_RESOURCE.
1606 valid = true;
1607 } else {
1608 LOGE("Invalid asset change operation: %{public}d", changeOperation);
1609 assetChangeOperations_.clear();
1610 addResourceTypes_.clear();
1611 return OHOS_INVALID_PARAM_CODE;
1612 }
1613
1614 if (!valid) {
1615 LOGE("Failed to apply asset change request, operation: %{public}d", changeOperation);
1616 assetChangeOperations_.clear();
1617 addResourceTypes_.clear();
1618 return 0;
1619 }
1620 appliedOperations.insert(changeOperation);
1621 }
1622 assetChangeOperations_.clear();
1623 addResourceTypes_.clear();
1624 return 0;
1625 }
1626 } // namespace Media
1627 } // namespace OHOS