1 /*
2  * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "picker/camera_picker_napi.h"
17 
18 #include <algorithm>
19 #include <memory>
20 #include <mutex>
21 #include <new>
22 #include <vector>
23 
24 #include "ability_lifecycle_callback.h"
25 #include "bool_wrapper.h"
26 #include "camera_device.h"
27 #include "camera_log.h"
28 #include "int_wrapper.h"
29 #include "js_native_api.h"
30 #include "napi/native_common.h"
31 #include "napi_base_context.h"
32 #include "string_wrapper.h"
33 
34 namespace OHOS {
35 namespace CameraStandard {
36 namespace {
37 constexpr char CAMERA_PICKER_BUNDLE_HAP_NAME[] = "com.huawei.hmos.camera";
38 constexpr char CAMERA_PICKER_BUNDLE_ABILITY_NAME[] = "PickerAbility";
39 constexpr char CAMERA_PICKER_ABILITY_ACTION_PHOTO[] = "ohos.want.action.imageCapture";
40 constexpr char CAMERA_PICKER_ABILITY_ACTION_VIDEO[] = "ohos.want.action.videoCapture";
41 const std::map<std::string, PickerMediaType> PICKER_MEDIA_TYPE_MAP = {
42     { "photo", PickerMediaType::PHOTO },
43     { "video", PickerMediaType::VIDEO },
44 };
45 constexpr char CAMERA_PICKER_NAPI_CLASS_NAME[] = "CameraPicker";
46 const char* const PICKER_MEDIA_TYPE[] = { "PHOTO", "VIDEO" };
47 const std::vector<std::string> PICKER_MEDIA_TYPE_VALUE = { "photo", "video" };
48 } // namespace
49 
50 using namespace std;
51 thread_local napi_ref CameraPickerNapi::sConstructor_ = nullptr;
52 thread_local napi_ref CameraPickerNapi::mediaTypeRef_ = nullptr;
53 thread_local uint32_t CameraPickerNapi::cameraPickerTaskId = CAMERA_PICKER_TASKID;
54 
CameraPickerNapi()55 CameraPickerNapi::CameraPickerNapi() : env_(nullptr)
56 {
57     CAMERA_SYNC_TRACE;
58 }
59 
~CameraPickerNapi()60 CameraPickerNapi::~CameraPickerNapi()
61 {
62     MEDIA_DEBUG_LOG("~CameraPickerNapi is called");
63 }
64 
GetAbilityContext(napi_env env,napi_value value)65 static std::shared_ptr<PickerContextProxy> GetAbilityContext(napi_env env, napi_value value)
66 {
67     MEDIA_DEBUG_LOG("GetAbilityContext is called");
68     bool stageMode = false;
69     napi_status status = OHOS::AbilityRuntime::IsStageContext(env, value, stageMode);
70     if (status != napi_ok || !stageMode) {
71         MEDIA_ERR_LOG("GetAbilityContext It is not stage Mode");
72         return nullptr;
73     }
74     auto context = AbilityRuntime::GetStageModeContext(env, value);
75     if (context == nullptr) {
76         MEDIA_ERR_LOG("GetAbilityContext get context failed context");
77         return nullptr;
78     }
79     auto contextProxy = std::make_shared<PickerContextProxy>(context);
80     if (contextProxy == nullptr || contextProxy->GetType() == PickerContextType::UNKNOWN) {
81         MEDIA_ERR_LOG("GetAbilityContext AbilityRuntime convert context failed");
82         return nullptr;
83     }
84     if (contextProxy->GetType() == PickerContextType::UI_EXTENSION) {
85         MEDIA_INFO_LOG("GetAbilityContext type is UI_EXTENSION");
86     } else if (contextProxy->GetType() == PickerContextType::ABILITY) {
87         MEDIA_INFO_LOG("GetAbilityContext type is ABILITY");
88     } else {
89         // Do nothing.
90     }
91     MEDIA_DEBUG_LOG("CameraPickerNapi GetAbilityContext success");
92     return contextProxy;
93 }
94 
GetMediaTypes(napi_env env,napi_value napiMediaTypesArray,std::vector<PickerMediaType> & mediaTypes)95 static bool GetMediaTypes(napi_env env, napi_value napiMediaTypesArray, std::vector<PickerMediaType>& mediaTypes)
96 {
97     MEDIA_DEBUG_LOG("GetMediaTypes is called");
98     uint32_t typeLen;
99     if (napi_get_array_length(env, napiMediaTypesArray, &typeLen) != napi_ok) {
100         MEDIA_ERR_LOG("napi_get_array_length failed");
101         return false;
102     }
103     for (uint32_t i = 0; i < typeLen; i++) {
104         napi_value element;
105         if (napi_get_element(env, napiMediaTypesArray, i, &element) != napi_ok) {
106             MEDIA_ERR_LOG("napi_get_element failed");
107             return false;
108         }
109         std::string typeString;
110         size_t stringSize = 0;
111         if (napi_get_value_string_utf8(env, element, nullptr, 0, &stringSize) != napi_ok) {
112             MEDIA_ERR_LOG("napi_get_value_string_utf8 failed");
113             return false;
114         }
115         typeString.reserve(stringSize + 1);
116         typeString.resize(stringSize);
117         if (napi_get_value_string_utf8(env, element, typeString.data(), (stringSize + 1), &stringSize) != napi_ok) {
118             MEDIA_ERR_LOG("napi_get_value_string_utf8 failed");
119             return false;
120         }
121         auto it = PICKER_MEDIA_TYPE_MAP.find(typeString.c_str());
122         if (it != PICKER_MEDIA_TYPE_MAP.end()) {
123             mediaTypes.emplace_back(it->second);
124         }
125     }
126     MEDIA_DEBUG_LOG("GetMediaTypes end valid size is %{public}zu", mediaTypes.size());
127     return true;
128 }
129 
GetPickerProfile(napi_env env,napi_value napiPickerProfile,PickerProfile & pickerProfile)130 static bool GetPickerProfile(napi_env env, napi_value napiPickerProfile, PickerProfile& pickerProfile)
131 {
132     MEDIA_DEBUG_LOG("GetPickerProfile is called");
133     napi_value value = nullptr;
134 
135     // get cameraPosition
136     if (napi_get_named_property(env, napiPickerProfile, "cameraPosition", &value) != napi_ok) {
137         MEDIA_ERR_LOG("napi_get_named_property failed");
138         return false;
139     }
140     int32_t cameraPosition = 0;
141     if (napi_get_value_int32(env, value, &cameraPosition) != napi_ok) {
142         MEDIA_WARNING_LOG("napi_get_value_int32 failed");
143     }
144     // get videoDuration
145     if (napi_get_named_property(env, napiPickerProfile, "videoDuration", &value) != napi_ok) {
146         MEDIA_ERR_LOG("napi_get_named_property failed");
147         return false;
148     }
149     int32_t videoDuration = 0;
150     if (napi_get_value_int32(env, value, &videoDuration) != napi_ok) {
151         MEDIA_WARNING_LOG("napi_get_value_int32 failed");
152     }
153     // get saveUri
154     char saveUri[PATH_MAX];
155     size_t length = 0;
156     if (napi_get_named_property(env, napiPickerProfile, "saveUri", &value) != napi_ok) {
157         MEDIA_ERR_LOG("napi_get_named_property failed");
158         return false;
159     }
160     if (napi_get_value_string_utf8(env, value, saveUri, PATH_MAX, &length) != napi_ok) {
161         MEDIA_WARNING_LOG("get saveUri fail!");
162     }
163     pickerProfile.cameraPosition = static_cast<CameraPosition>(cameraPosition);
164     pickerProfile.videoDuration = videoDuration;
165     pickerProfile.saveUri = std::string(saveUri);
166     MEDIA_INFO_LOG("GetPickerProfile cameraPosition: %{public}d, duration: %{public}d", cameraPosition, videoDuration);
167     MEDIA_INFO_LOG("GetPickerProfile saveUri: %{public}s", saveUri);
168     return true;
169 }
170 
SetPickerWantParams(AAFwk::Want & want,std::shared_ptr<PickerContextProxy> & pickerContextProxy,const vector<PickerMediaType> & mediaTypes,PickerProfile & pickerProfile)171 static void SetPickerWantParams(AAFwk::Want& want, std::shared_ptr<PickerContextProxy>& pickerContextProxy,
172     const vector<PickerMediaType>& mediaTypes, PickerProfile& pickerProfile)
173 {
174     MEDIA_DEBUG_LOG("SetPickerWantParams enter");
175     AAFwk::WantParams wantParam;
176     bool isPhotoType = false;
177     bool isVideoType = false;
178     for (auto type : mediaTypes) {
179         MEDIA_INFO_LOG("SetPickerWantParams current type is:%{public}d", type);
180         switch (type) {
181             case PickerMediaType::PHOTO:
182                 isPhotoType = true;
183                 break;
184             case PickerMediaType::VIDEO:
185                 isVideoType = true;
186                 break;
187         }
188     }
189 
190     want.SetElementName(CAMERA_PICKER_BUNDLE_HAP_NAME, CAMERA_PICKER_BUNDLE_ABILITY_NAME);
191     want.SetUri(pickerProfile.saveUri);
192     want.SetFlags(AAFwk::Want::FLAG_AUTH_READ_URI_PERMISSION | AAFwk::Want::FLAG_AUTH_WRITE_URI_PERMISSION);
193     wantParam.SetParam("ability.want.params.uiExtensionTargetType", AAFwk::String::Box("cameraPicker"));
194     wantParam.SetParam("callBundleName", AAFwk::String::Box(pickerContextProxy->GetBundleName().c_str()));
195     wantParam.SetParam("cameraPosition", AAFwk::Integer::Box(pickerProfile.cameraPosition));
196     wantParam.SetParam("videoDuration", AAFwk::Integer::Box(pickerProfile.videoDuration));
197     wantParam.SetParam("saveUri", AAFwk::String::Box(pickerProfile.saveUri.c_str()));
198     if (isPhotoType && isVideoType) {
199         wantParam.SetParam("supportMultiMode", AAFwk::Boolean::Box(true));
200     }
201     want.SetParams(wantParam);
202     if (isPhotoType) {
203         want.SetAction(CAMERA_PICKER_ABILITY_ACTION_PHOTO);
204     } else if (isVideoType) {
205         want.SetAction(CAMERA_PICKER_ABILITY_ACTION_VIDEO);
206     } else {
207         MEDIA_ERR_LOG("SetPickerWantParams set action fail!");
208     }
209     MEDIA_DEBUG_LOG("SetPickerWantParams end");
210 }
211 
CommonCompleteCallback(napi_env env,napi_status status,void * data)212 static void CommonCompleteCallback(napi_env env, napi_status status, void* data)
213 {
214     MEDIA_INFO_LOG("CommonCompleteCallback is called");
215     napi_value callbackObj = nullptr;
216     napi_value resultCode = nullptr;
217     napi_value resultUri = nullptr;
218     napi_value resultMediaType = nullptr;
219     auto context = static_cast<CameraPickerAsyncContext*>(data);
220     if (context == nullptr) {
221         MEDIA_ERR_LOG("Async context is null");
222         return;
223     }
224 
225     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
226 
227     if (!context->status) {
228         CameraNapiUtils::CreateNapiErrorObject(env, context->errorCode, context->errorMsg.c_str(), jsContext);
229     } else {
230         jsContext->status = true;
231         napi_get_undefined(env, &jsContext->error);
232         if (!context->bRetBool) {
233             napi_create_object(env, &callbackObj);
234             napi_create_int32(env, context->uiExtCallback->GetResultCode(), &resultCode);
235             napi_set_named_property(env, callbackObj, "resultCode", resultCode);
236             napi_create_string_utf8(env, context->uiExtCallback->GetResultUri().c_str(), NAPI_AUTO_LENGTH, &resultUri);
237             napi_set_named_property(env, callbackObj, "resultUri", resultUri);
238             napi_create_string_utf8(
239                 env, context->uiExtCallback->GetResultMediaType().c_str(), NAPI_AUTO_LENGTH, &resultMediaType);
240             napi_set_named_property(env, callbackObj, "mediaType", resultMediaType);
241             jsContext->data = callbackObj;
242         } else {
243             napi_get_undefined(env, &jsContext->data);
244         }
245     }
246 
247     if (!context->funcName.empty() && context->taskId > 0) {
248         // Finish async trace
249         CAMERA_FINISH_ASYNC_TRACE(context->funcName, context->taskId);
250         jsContext->funcName = context->funcName;
251     }
252 
253     if (context->work != nullptr) {
254         CameraNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef, context->work, *jsContext);
255     }
256     delete context;
257 }
258 
StartCameraAbility(napi_env env,std::shared_ptr<PickerContextProxy> pickerContextProxy,AAFwk::Want & want)259 static std::shared_ptr<UIExtensionCallback> StartCameraAbility(
260     napi_env env, std::shared_ptr<PickerContextProxy> pickerContextProxy, AAFwk::Want& want)
261 {
262     auto uiExtCallback = std::make_shared<UIExtensionCallback>(pickerContextProxy);
263     OHOS::Ace::ModalUIExtensionCallbacks extensionCallbacks = {
264         [uiExtCallback](int32_t releaseCode) { uiExtCallback->OnRelease(releaseCode); },
265         [uiExtCallback](int32_t resultCode, const OHOS::AAFwk::Want& result) {
266             uiExtCallback->OnResult(resultCode, result); },
267         [uiExtCallback](const OHOS::AAFwk::WantParams& request) { uiExtCallback->OnReceive(request); },
268         [uiExtCallback](int32_t errorCode, const std::string& name, const std::string& message) {
269             uiExtCallback->OnError(errorCode, name, message); },
270         [uiExtCallback](const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy>& uiProxy) {
271             uiExtCallback->OnRemoteReady(uiProxy); },
272         [uiExtCallback]() { uiExtCallback->OnDestroy(); }
273     };
274 
275     AbilityRuntime::RuntimeTask task = [extensionCallbacks](
276                                            const int32_t code, const AAFwk::Want& returnWant, bool isInner) {
277         if (code == 0) {
278             extensionCallbacks.onResult(0, returnWant);
279         } else {
280             extensionCallbacks.onError(code, "", "");
281         }
282         MEDIA_INFO_LOG("picker StartCameraAbility get result %{public}d %{public}d", code, isInner);
283     };
284 
285     auto ret = pickerContextProxy->StartAbilityForResult(want, 1, std::move(task));
286     if (ret != ERR_OK) {
287         MEDIA_ERR_LOG("picker StartCameraAbility picker StartCameraAbility is %{public}d", ret);
288         return nullptr;
289     }
290     return uiExtCallback;
291 }
292 
StartAsyncWork(napi_env env,CameraPickerAsyncContext * pickerAsyncCtx)293 static napi_status StartAsyncWork(napi_env env, CameraPickerAsyncContext* pickerAsyncCtx)
294 {
295     napi_value resource = nullptr;
296     CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Pick");
297     MEDIA_INFO_LOG("CameraPicker StartAsyncWork");
298     return napi_create_async_work(
299         env, nullptr, resource,
300         [](napi_env env, void* data) {
301             MEDIA_INFO_LOG("CameraPicker wait result begin");
302             auto context = static_cast<CameraPickerAsyncContext*>(data);
303             context->status = false;
304             // Start async trace
305 
306             CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
307             context->bRetBool = false;
308 
309             context->uiExtCallback->WaitResultLock();
310             MEDIA_INFO_LOG("CameraPicker wait result end");
311             context->status = true;
312         },
313         CommonCompleteCallback, static_cast<void*>(pickerAsyncCtx), &pickerAsyncCtx->work);
314 }
315 
Pick(napi_env env,napi_callback_info cbInfo)316 napi_value CameraPickerNapi::Pick(napi_env env, napi_callback_info cbInfo)
317 {
318     MEDIA_INFO_LOG("CameraPicker::Pick is called");
319     CAMERA_SYNC_TRACE;
320     napi_value result = nullptr;
321     size_t argc = ARGS_THREE;
322     napi_value argv[ARGS_THREE];
323     napi_value thisVar = nullptr;
324 
325     napi_get_undefined(env, &result);
326     if (napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, nullptr) != napi_ok) {
327         MEDIA_ERR_LOG("napi_get_cb_info failed");
328         return result;
329     }
330 
331     if (argc < ARGS_THREE) {
332         MEDIA_ERR_LOG("the parameter of number should be at least three");
333         return result;
334     }
335 
336     std::unique_ptr<CameraPickerAsyncContext> asyncCtx = std::make_unique<CameraPickerAsyncContext>();
337     asyncCtx->funcName = "CameraPickerNapi::Pick";
338     asyncCtx->taskId = CameraNapiUtils::IncrementAndGet(cameraPickerTaskId);
339     asyncCtx->contextProxy = GetAbilityContext(env, argv[ARGS_ZERO]);
340     if (asyncCtx->contextProxy == nullptr) {
341         MEDIA_ERR_LOG("GetAbilityContext failed");
342         return result;
343     }
344 
345     std::vector<PickerMediaType> mediaTypes;
346     if (!GetMediaTypes(env, argv[ARGS_ONE], mediaTypes)) {
347         MEDIA_ERR_LOG("GetMediaTypes failed");
348         return result;
349     }
350 
351     if (!GetPickerProfile(env, argv[ARGS_TWO], asyncCtx->pickerProfile)) {
352         MEDIA_ERR_LOG("GetPhotoProfiles failed");
353         return result;
354     }
355     SetPickerWantParams(asyncCtx->want, asyncCtx->contextProxy, mediaTypes, asyncCtx->pickerProfile);
356     asyncCtx->uiExtCallback = StartCameraAbility(env, asyncCtx->contextProxy, asyncCtx->want);
357     if (asyncCtx->uiExtCallback == nullptr) {
358         MEDIA_ERR_LOG("StartCameraAbility failed");
359         return result;
360     }
361     CAMERA_NAPI_CREATE_PROMISE(env, asyncCtx->callbackRef, asyncCtx->deferred, result);
362     if (StartAsyncWork(env, asyncCtx.get()) != napi_ok) {
363         MEDIA_ERR_LOG("Failed to create napi_create_async_work for Pick");
364         napi_get_undefined(env, &result);
365     } else {
366         napi_queue_async_work_with_qos(env, asyncCtx->work, napi_qos_user_initiated);
367         asyncCtx.release();
368     }
369     return result;
370 }
371 
Init(napi_env env,napi_value exports)372 napi_value CameraPickerNapi::Init(napi_env env, napi_value exports)
373 {
374     MEDIA_INFO_LOG("CameraPickerNapi::Init is called");
375     napi_status status;
376     napi_value ctorObj;
377     int32_t refCount = 1;
378 
379     napi_property_descriptor camera_picker_props[] = {};
380 
381     napi_property_descriptor camera_picker_static_props[] = {
382         DECLARE_NAPI_STATIC_FUNCTION("pick", Pick),
383         DECLARE_NAPI_PROPERTY("PickerMediaType", CreatePickerMediaType(env)),
384         DECLARE_NAPI_STATIC_PROPERTY("PickerProfile", CreatePickerProfile(env)),
385         DECLARE_NAPI_STATIC_PROPERTY("PickerResult", CreatePickerResult(env)),
386     };
387 
388     status = napi_define_class(env, CAMERA_PICKER_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH, CameraPickerNapiConstructor,
389         nullptr, sizeof(camera_picker_props) / sizeof(camera_picker_props[PARAM0]), camera_picker_props, &ctorObj);
390     if (status == napi_ok) {
391         if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
392             status = napi_set_named_property(env, exports, CAMERA_PICKER_NAPI_CLASS_NAME, ctorObj);
393             if (status == napi_ok &&
394                 napi_define_properties(env, exports,
395                     sizeof(camera_picker_static_props) / sizeof(camera_picker_static_props[PARAM0]),
396                     camera_picker_static_props) == napi_ok) {
397                 return exports;
398             }
399         }
400     }
401     MEDIA_ERR_LOG("Init call Failed!");
402     return nullptr;
403 }
404 
CreatePickerProfile(napi_env env)405 napi_value CameraPickerNapi::CreatePickerProfile(napi_env env)
406 {
407     MEDIA_DEBUG_LOG("CreatePickerProfile is called");
408     napi_value result = nullptr;
409     napi_status status;
410     napi_property_descriptor pickerProfileProps[] = {
411         DECLARE_NAPI_PROPERTY("cameraPosition", nullptr),
412         DECLARE_NAPI_PROPERTY("saveUri", nullptr),
413         DECLARE_NAPI_PROPERTY("videoDuration", nullptr),
414     };
415 
416     status = napi_define_class(
417         env, "PickerProfile", NAPI_AUTO_LENGTH,
418         [](napi_env env, napi_callback_info info) {
419             MEDIA_DEBUG_LOG("PickerProfileConstructor is called");
420             napi_status status;
421             napi_value result = nullptr;
422             napi_value thisVar = nullptr;
423 
424             napi_get_undefined(env, &result);
425             CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
426             if (status == napi_ok) {
427                 return thisVar;
428             }
429             return result;
430         },
431         nullptr, sizeof(pickerProfileProps) / sizeof(pickerProfileProps[PARAM0]), pickerProfileProps, &result);
432     if (status != napi_ok) {
433         MEDIA_DEBUG_LOG("CreatePickerProfile class fail");
434         napi_get_undefined(env, &result);
435     }
436     return result;
437 }
438 
CreatePickerMediaType(napi_env env)439 napi_value CameraPickerNapi::CreatePickerMediaType(napi_env env)
440 {
441     MEDIA_DEBUG_LOG("CreatePickerMediaType is called");
442     napi_value result = nullptr;
443     napi_status status;
444     if (mediaTypeRef_ != nullptr) {
445         status = napi_get_reference_value(env, mediaTypeRef_, &result);
446         if (status == napi_ok) {
447             return result;
448         }
449     }
450     status = CameraNapiUtils::CreateObjectWithPropNameAndValues(env, &result,
451         sizeof(PICKER_MEDIA_TYPE) / sizeof(PICKER_MEDIA_TYPE[0]), const_cast<const char**>(PICKER_MEDIA_TYPE),
452         PICKER_MEDIA_TYPE_VALUE);
453     if (status != napi_ok) {
454         MEDIA_DEBUG_LOG("CreatePickerMediaType call end!");
455         napi_get_undefined(env, &result);
456     } else {
457         napi_create_reference(env, result, 1, &mediaTypeRef_);
458     }
459     return result;
460 }
461 
CreatePickerResult(napi_env env)462 napi_value CameraPickerNapi::CreatePickerResult(napi_env env)
463 {
464     MEDIA_DEBUG_LOG("CreatePickerResult is called");
465     napi_value result = nullptr;
466     napi_status status;
467     napi_property_descriptor pickerResultProps[] = {
468         DECLARE_NAPI_PROPERTY("resultCode", nullptr),
469         DECLARE_NAPI_PROPERTY("resultUri", nullptr),
470         DECLARE_NAPI_PROPERTY("mediaType", nullptr),
471     };
472 
473     status = napi_define_class(
474         env, "PickerResult", NAPI_AUTO_LENGTH,
475         [](napi_env env, napi_callback_info info) {
476             MEDIA_DEBUG_LOG("PickerResultConstructor is called");
477             napi_status status;
478             napi_value result = nullptr;
479             napi_value thisVar = nullptr;
480 
481             napi_get_undefined(env, &result);
482             CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
483             if (status == napi_ok) {
484                 return thisVar;
485             }
486             return result;
487         },
488         nullptr, sizeof(pickerResultProps) / sizeof(pickerResultProps[PARAM0]), pickerResultProps, &result);
489     if (status != napi_ok) {
490         MEDIA_DEBUG_LOG("CreatePickerResult class fail");
491         napi_get_undefined(env, &result);
492     }
493     return result;
494 }
495 
496 // Constructor callback
CameraPickerNapiConstructor(napi_env env,napi_callback_info info)497 napi_value CameraPickerNapi::CameraPickerNapiConstructor(napi_env env, napi_callback_info info)
498 {
499     MEDIA_DEBUG_LOG("CameraPickerNapiConstructor is called");
500     napi_status status;
501     napi_value result = nullptr;
502     napi_value thisVar = nullptr;
503 
504     napi_get_undefined(env, &result);
505     CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
506 
507     if (status == napi_ok && thisVar != nullptr) {
508         std::unique_ptr<CameraPickerNapi> obj = std::make_unique<CameraPickerNapi>();
509         obj->env_ = env;
510         status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
511             CameraPickerNapi::CameraPickerNapiDestructor, nullptr, nullptr);
512         if (status == napi_ok) {
513             obj.release();
514             return thisVar;
515         } else {
516             MEDIA_ERR_LOG("Failure wrapping js to native napi");
517         }
518     }
519     MEDIA_ERR_LOG("CameraPickerNapiConstructor call Failed!");
520     return result;
521 }
522 
CameraPickerNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)523 void CameraPickerNapi::CameraPickerNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
524 {
525     MEDIA_DEBUG_LOG("CameraPickerNapiDestructor is called");
526     CameraPickerNapi* camera = reinterpret_cast<CameraPickerNapi*>(nativeObject);
527     if (camera != nullptr) {
528         delete camera;
529     }
530 }
531 
UIExtensionCallback(std::shared_ptr<PickerContextProxy> contextProxy)532 UIExtensionCallback::UIExtensionCallback(std::shared_ptr<PickerContextProxy> contextProxy) : contextProxy_(contextProxy)
533 {}
534 
FinishPicker(int32_t code)535 bool UIExtensionCallback::FinishPicker(int32_t code)
536 {
537     {
538         std::unique_lock<std::mutex> lock(cbMutex_);
539         if (isCallbackReturned_) {
540             MEDIA_ERR_LOG("alreadyCallback");
541             return false;
542         }
543         isCallbackReturned_ = true;
544     }
545     resultCode_ = code;
546     CloseWindow();
547     NotifyResultLock();
548     return true;
549 }
550 
OnRelease(int32_t releaseCode)551 void UIExtensionCallback::OnRelease(int32_t releaseCode)
552 {
553     MEDIA_INFO_LOG("UIExtensionComponent OnRelease(), releaseCode = %{public}d", releaseCode);
554     FinishPicker(releaseCode);
555 }
556 
OnResult(int32_t resultCode,const OHOS::AAFwk::Want & result)557 void UIExtensionCallback::OnResult(int32_t resultCode, const OHOS::AAFwk::Want& result)
558 {
559     const AAFwk::WantParams& wantParams = result.GetParams();
560     std::string uri = wantParams.GetStringParam("resourceUri");
561     std::string resourceMode = wantParams.GetStringParam("mode");
562     MEDIA_INFO_LOG("OnResult is called,resultCode = %{public}d, uri = %{public}s ,CaptureMode:%{public}s", resultCode,
563         uri.c_str(), resourceMode.c_str());
564     resultUri_ = uri;
565     resultMode_ = resourceMode;
566     FinishPicker(resultCode);
567 }
568 
OnReceive(const OHOS::AAFwk::WantParams & request)569 void UIExtensionCallback::OnReceive(const OHOS::AAFwk::WantParams& request)
570 {
571     MEDIA_INFO_LOG("UIExtensionComponent OnReceive()");
572 }
573 
OnError(int32_t errorCode,const std::string & name,const std::string & message)574 void UIExtensionCallback::OnError(int32_t errorCode, const std::string& name, const std::string& message)
575 {
576     MEDIA_INFO_LOG("UIExtensionComponent OnError(), errorCode = %{public}d, name = %{public}s, message = %{public}s",
577         errorCode, name.c_str(), message.c_str());
578     FinishPicker(errorCode);
579 }
580 
OnRemoteReady(const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy> & uiProxy)581 void UIExtensionCallback::OnRemoteReady(const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy>& uiProxy)
582 {
583     MEDIA_INFO_LOG("UIExtensionComponent OnRemoteReady()");
584 }
585 
OnDestroy()586 void UIExtensionCallback::OnDestroy()
587 {
588     MEDIA_INFO_LOG("UIExtensionComponent OnDestroy()");
589     FinishPicker(0);
590 }
591 
CloseWindow()592 void UIExtensionCallback::CloseWindow()
593 {
594     MEDIA_INFO_LOG("start CloseWindow");
595     if (contextProxy_ == nullptr) {
596         MEDIA_ERR_LOG("contextProxy_ is nullptr");
597         return;
598     }
599     if (sessionId_ == 0) {
600         MEDIA_WARNING_LOG("sessionId_ is 0");
601         return;
602     }
603     auto uiContent = contextProxy_->GetUIContent();
604     if (uiContent != nullptr) {
605         MEDIA_INFO_LOG("CloseModalUIExtension");
606         uiContent->CloseModalUIExtension(sessionId_);
607     }
608 }
609 } // namespace CameraStandard
610 } // namespace OHOS