* Copyright (C) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "contacts_napi_utils.h"
#include "hilog_wrapper_api.h"
#include "ability.h"
#include "ability_context.h"
#include "context.h"
#include "ui_content.h"
#include "ui_extension_context.h"
#include "want.h"
namespace OHOS {
namespace ContactsApi {
static constexpr const char *JS_ERROR_INVALID_INPUT_PARAMETER_STRING =
"parameter error. Mandatory parameters are left unspecified.";
static constexpr const char *JS_ERROR_VERIFICATION_FAILED_PARAMETER_STRING =
"parameter error. The type of id must be number.";
static constexpr const char *JS_ERROR_INVALID_PARAMETER_STRING =
"parameter error. Invalid parameter value.";
static constexpr const char *JS_ERROR_PERMISSION_DENIED_STRING = "Permission denied";
napi_value ContactsNapiUtils::ToInt32Value(napi_env env, int32_t value)
{
napi_value staticValue = nullptr;
napi_create_int32(env, value, &staticValue);
return staticValue;
}
napi_value ContactsNapiUtils::CreateClassConstructor(napi_env env, napi_callback_info info)
{
napi_value thisArg = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
napi_value global = nullptr;
napi_get_global(env, &global);
return thisArg;
}
bool ContactsNapiUtils::MatchValueType(napi_env env, napi_value value, napi_valuetype targetType)
{
napi_valuetype valueType = napi_undefined;
napi_typeof(env, value, &valueType);
return valueType == targetType;
}
bool ContactsNapiUtils::MatchParameters(
napi_env env, const napi_value parameters[], std::initializer_list<napi_valuetype> valueTypes)
{
if (parameters == nullptr) {
return false;
}
int i = 0;
for (auto beg = valueTypes.begin(); beg != valueTypes.end(); ++beg) {
if (!MatchValueType(env, parameters[i], *beg)) {
return false;
}
++i;
}
return true;
}
napi_value ContactsNapiUtils::CreateError(napi_env env, int32_t err)
{
napi_value businessError = nullptr;
napi_value errorCode = nullptr;
napi_value errorMessage = nullptr;
if (err == PERMISSION_ERROR) {
napi_create_string_utf8(env, JS_ERROR_PERMISSION_DENIED_STRING, NAPI_AUTO_LENGTH, &errorMessage);
} else if (err == PARAMETER_ERROR) {
napi_create_string_utf8(env, JS_ERROR_INVALID_INPUT_PARAMETER_STRING, NAPI_AUTO_LENGTH, &errorMessage);
} else if (err == INVALID_PARAMETER) {
napi_create_string_utf8(env, JS_ERROR_INVALID_PARAMETER_STRING, NAPI_AUTO_LENGTH, &errorMessage);
}
napi_create_int32(env, err, &errorCode);
napi_create_error(env, nullptr, errorMessage, &businessError);
napi_set_named_property(env, businessError, "code", errorCode);
HILOG_INFO("CreateError end");
return businessError;
}
napi_value ContactsNapiUtils::CreateErrorByVerification(napi_env env, int32_t err)
{
napi_value businessError = nullptr;
napi_value errorCode = nullptr;
napi_value errorMessage = nullptr;
if (err == PERMISSION_ERROR) {
napi_create_string_utf8(env, JS_ERROR_PERMISSION_DENIED_STRING, NAPI_AUTO_LENGTH, &errorMessage);
} else if (err == PARAMETER_ERROR) {
napi_create_string_utf8(env, JS_ERROR_VERIFICATION_FAILED_PARAMETER_STRING, NAPI_AUTO_LENGTH, &errorMessage);
} else if (err == INVALID_PARAMETER) {
napi_create_string_utf8(env, JS_ERROR_INVALID_PARAMETER_STRING, NAPI_AUTO_LENGTH, &errorMessage);
}
napi_create_int32(env, err, &errorCode);
napi_create_error(env, nullptr, errorMessage, &businessError);
napi_set_named_property(env, businessError, "code", errorCode);
HILOG_INFO("CreateErrorByVerification end");
return businessError;
}
OHOS::Ace::UIContent* ContactsNapiUtils::GetUIContent(
std::unique_ptr<OHOS::ContactsApi::BaseContext>& asyncContext)
{
OHOS::Ace::UIContent* uiContent = nullptr;
if (asyncContext->context != nullptr) {
HILOG_INFO("get uiContext by ability context");
uiContent = asyncContext->context->GetUIContent();
} else if (asyncContext->uiExtensionContext != nullptr) {
HILOG_INFO("get uiContext by uiExtensionContext");
uiContent = asyncContext->uiExtensionContext->GetUIContent();
} else {
HILOG_ERROR("get uiContext failed.");
}
HILOG_INFO("ContactsNapiUtils::GetUIContent END");
return uiContent;
}
napi_status ContactsNapiUtils::GetParamCallback(napi_env env,
std::unique_ptr<OHOS::ContactsApi::BaseContext> &context, size_t argc, napi_value argv[])
{
bool isCallback = false;
CHECK_STATUS_RET(HasCallback(env, argc, argv, isCallback), "Failed to check callback");
if (isCallback) {
CHECK_STATUS_RET(GetParamFunction(env, argv[argc - 1], context->callbackRef),
"Failed to get callback");
}
return napi_ok;
}
void ContactsNapiUtils::InvokeJSAsyncMethod(napi_env env, napi_deferred deferred, napi_ref callbackRef,
napi_async_work work, const JSAsyncContextOutput &asyncContext)
{
napi_value retVal;
napi_value callback = nullptr;
if (deferred) {
if (asyncContext.status) {
napi_resolve_deferred(env, deferred, asyncContext.data);
} else {
napi_reject_deferred(env, deferred, asyncContext.error);
}
} else {
napi_value result[ARGS_TWO];
result[PARAM0] = asyncContext.error;
result[PARAM1] = asyncContext.data;
napi_get_reference_value(env, callbackRef, &callback);
napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal);
napi_delete_reference(env, callbackRef);
}
napi_delete_async_work(env, work);
}
napi_value ContactsNapiUtils::NapiCreateAsyncWork(napi_env env,
std::unique_ptr<ContactsApi::BaseContext> &asyncContext, const std::string &resourceName,
void (*execute)(napi_env, void *), void (*complete)(napi_env, napi_status, void *))
{
napi_value result = nullptr;
napi_value resource = nullptr;
NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
NAPI_CREATE_RESOURCE_NAME(env, resource, resourceName.c_str());
NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, execute, complete,
static_cast<void *>(asyncContext.get()), &asyncContext->work));
NAPI_CALL(env, napi_queue_async_work(env, asyncContext->work));
asyncContext.release();
return result;
}
napi_status ContactsNapiUtils::HasCallback(napi_env env, const size_t argc, const napi_value argv[],
bool &isCallback)
{
isCallback = false;
if (argc < ARGS_ONE) {
return napi_ok;
}
napi_valuetype valueType = napi_undefined;
napi_status statusRet = napi_typeof(env, argv[argc - 1], &valueType);
if (statusRet != napi_ok) {
return statusRet;
}
isCallback = (valueType == napi_function);
return napi_ok;
}
napi_status ContactsNapiUtils::GetParamFunction(napi_env env, napi_value arg, napi_ref &callbackRef)
{
napi_valuetype valueType = napi_undefined;
napi_status statusRet = napi_typeof(env, arg, &valueType);
if (statusRet != napi_ok) {
return statusRet;
}
CHECK_COND_RET(valueType == napi_function, napi_function_expected, "Type is not as expected function");
statusRet = napi_create_reference(env, arg, NAPI_INIT_REF_COUNT, &callbackRef);
if (statusRet != napi_ok) {
return statusRet;
}
return napi_ok;
}
void ContactsNapiUtils::ThrowError(napi_env env, int32_t err, const std::string &errMsg)
{
std::string message = errMsg;
if (message.empty()) {
message = "operation not support";
}
HILOG_ERROR("ThrowError errCode:%{public}d errMsg:%{public}s", err, message.c_str());
NAPI_CALL_RETURN_VOID(env, napi_throw_error(env, std::to_string(err).c_str(), message.c_str()));
}
void ContactsNapiUtils::ThrowError(napi_env env, int32_t err,
const char *funcName, int32_t line, const std::string &errMsg)
{
std::string message = errMsg;
if (message.empty()) {
message = "operation not support";
}
HILOG_ERROR("{%{public}s:%d} ThrowError errCode:%{public}d errMsg:%{public}s", funcName, line,
err, message.c_str());
NAPI_CALL_RETURN_VOID(env, napi_throw_error(env, std::to_string(err).c_str(), message.c_str()));
}
ModalUICallback::ModalUICallback(Ace::UIContent* uiContent,
std::unique_ptr<OHOS::ContactsApi::BaseContext>& baseContext)
{
this->uiContent = uiContent;
this->baseContext = baseContext.get();
this->pickerCallBack_ = baseContext->pickerCallBack.get();
}
void ModalUICallback::SetSessionId(int32_t sessionId)
{
this->sessionId_=sessionId;
}
void ModalUICallback::OnRelease(int32_t releaseCode)
{
HILOG_INFO("OnRelease enter. release code is %{public}d", releaseCode);
this->uiContent->CloseModalUIExtension(this->sessionId_);
this->pickerCallBack_->ready = true;
}
void ModalUICallback::OnError(int32_t code, const std::string& name, const std::string& message)
{
HILOG_ERROR("OnError enter. errorCode=%{public}d, name=%{public}s, message=%{public}s",
code, name.c_str(), message.c_str());
if (!this->pickerCallBack_->ready) {
this->uiContent->CloseModalUIExtension(this->sessionId_);
this->pickerCallBack_->ready = true;
}
}
void ModalUICallback::OnResultForModal(int32_t resultCode, const OHOS::AAFwk::Want &result)
{
HILOG_INFO("OnResultForModal enter. resultCode is %{public}d", resultCode);
this->pickerCallBack_->resultCode = resultCode;
}
void ModalUICallback::OnReceive(const OHOS::AAFwk::WantParams &request)
{
HILOG_INFO("OnReceive enter.");
bool isFromSaveContactPicker = request.GetParam("isFromSaveContactPicker");
if (isFromSaveContactPicker) {
int32_t contactIndex = request.GetIntParam("contactIndex", -1);
this->pickerCallBack_->dataIndex = contactIndex;
this->uiContent->CloseModalUIExtension(this->sessionId_);
this->pickerCallBack_->ready = true;
HILOG_WARN("%{public}s isFromSaveContactPicker contactIndex : %{public}d ",
__func__, contactIndex);
} else {
int32_t tempIndex = request.GetIntParam("index", -1);
this->pickerCallBack_->dataIndex =
(this->pickerCallBack_->dataIndex < tempIndex ? tempIndex : this->pickerCallBack_->dataIndex);
this->pickerCallBack_->total = request.GetIntParam("total", -1);
if (tempIndex <= (PICKER_MAX - 1) && tempIndex >= 0) {
this->pickerCallBack_->pickerData[tempIndex] = request.GetStringParam("pickerData");
}
HILOG_WARN("%{public}s total : %{public}d index : %{public}d "
"tempIndex : %{public}d pickerData size %{public}zu",
__func__, this->pickerCallBack_->total, this->pickerCallBack_->dataIndex, tempIndex,
sizeof(this->pickerCallBack_->pickerData));
}
}
void ModalUICallback::OnDestroy()
{
HILOG_INFO("OnDestroy enter.");
}
SyncModalCallback::SyncModalCallback(Ace::UIContent* uiContent, SyncDialogCallback* syncCallback)
{
this->uiContent_ = uiContent;
this->syncCallback_ = syncCallback;
}
void SyncModalCallback::SetSessionId(int32_t sessionId)
{
this->sessionId_ = sessionId;
}
void SyncModalCallback::OnRelease(int32_t releaseCode)
{
if (this->uiContent_ != nullptr) {
this->uiContent_->CloseModalUIExtension(this->sessionId_);
}
if (this->syncCallback_ != nullptr) {
std::lock_guard<std::mutex> lock(this->syncCallback_->mutex);
if (this->syncCallback_->confirmResult == CONFIRM_RESULT_NO) {
this->syncCallback_->confirmResult = CONFIRM_RESULT_CANCELLED;
}
this->syncCallback_->ready = true;
this->syncCallback_->cv.notify_one();
}
}
void SyncModalCallback::OnError(int32_t code, const std::string &name, const std::string &message)
{
if (this->syncCallback_ != nullptr && !this->syncCallback_->ready) {
if (this->uiContent_ != nullptr) {
this->uiContent_->CloseModalUIExtension(this->sessionId_);
}
{
std::lock_guard<std::mutex> lock(this->syncCallback_->mutex);
this->syncCallback_->ready = true;
this->syncCallback_->confirmResult = CONFIRM_RESULT_CANCELLED;
this->syncCallback_->cv.notify_one();
}
}
}
void SyncModalCallback::OnResultForModal(int32_t resultCode, const OHOS::AAFwk::Want &result)
{
if (this->uiContent_ != nullptr) {
this->uiContent_->CloseModalUIExtension(this->sessionId_);
}
}
void SyncModalCallback::OnReceive(const OHOS::AAFwk::WantParams &request)
{
if (this->syncCallback_ != nullptr) {
int32_t confirmResult = request.GetIntParam("confirmResult", CONFIRM_RESULT_NO);
{
std::lock_guard<std::mutex> lock(this->syncCallback_->mutex);
this->syncCallback_->ready = true;
this->syncCallback_->confirmResult = confirmResult;
this->syncCallback_->cv.notify_one();
}
}
}
void SyncModalCallback::OnDestory()
{
}
}
}