diff --git a/frameworks/js/napi/accesstoken/src/napi_request_global_switch_on_setting.cpp b/frameworks/js/napi/accesstoken/src/napi_request_global_switch_on_setting.cpp index e6b05b6d271c4c22c920388b1bc36388356aac6c..ceb3fe322ea03abf61a6d299d83452887cd1cc35 100644 --- a/frameworks/js/napi/accesstoken/src/napi_request_global_switch_on_setting.cpp +++ b/frameworks/js/napi/accesstoken/src/napi_request_global_switch_on_setting.cpp @@ -24,6 +24,9 @@ namespace OHOS { namespace Security { namespace AccessToken { +std::map>> + RequestGlobalSwitchAsyncInstanceControl::instanceIdMap_; +std::mutex RequestGlobalSwitchAsyncInstanceControl::instanceIdMutex_; namespace { const std::string GLOBAL_SWITCH_KEY = "ohos.user.setting.global_switch"; const std::string GLOBAL_SWITCH_RESULT_KEY = "ohos.user.setting.global_switch.result"; @@ -199,6 +202,8 @@ void SwitchOnSettingUICallback::ReleaseHandler(int32_t code) if (code == -1) { this->reqContext_->errorCode = code; } + RequestGlobalSwitchAsyncInstanceControl::UpdateQueueData(this->reqContext_); + RequestGlobalSwitchAsyncInstanceControl::ExecCallback(this->reqContext_->instanceId); GlobalSwitchResultsCallbackUI( TransferToJsErrorCode(this->reqContext_->errorCode), this->reqContext_->switchStatus, this->reqContext_); } @@ -356,6 +361,117 @@ static int32_t StartUIExtension(std::shared_ptr return CreateUIExtension(want, asyncContext); } +static void GetInstanceId(std::shared_ptr& asyncContext) +{ + auto task = [asyncContext]() { + Ace::UIContent* uiContent = GetUIContent(asyncContext); + if (uiContent == nullptr) { + LOGE(ATM_DOMAIN, ATM_TAG, "Get ui content failed!"); + return; + } + asyncContext->instanceId = uiContent->GetInstanceId(); + }; +#ifdef EVENTHANDLER_ENABLE + if (asyncContext->handler_ != nullptr) { + asyncContext->handler_->PostSyncTask(task, "AT:GetInstanceId"); + } else { + task(); + } +#else + task(); +#endif + LOGI(ATM_DOMAIN, ATM_TAG, "Instance id: %{public}d", asyncContext->instanceId); +} + +void RequestGlobalSwitchAsyncInstanceControl::AddCallbackByInstanceId( + std::shared_ptr& asyncContext) +{ + LOGI(ATM_DOMAIN, ATM_TAG, "InstanceId: %{public}d", asyncContext->instanceId); + { + std::lock_guard lock(instanceIdMutex_); + auto iter = instanceIdMap_.find(asyncContext->instanceId); + // id is existed mean a pop window is showing, add context to waiting queue + if (iter != instanceIdMap_.end()) { + LOGI(ATM_DOMAIN, ATM_TAG, "InstanceId: %{public}d has existed.", asyncContext->instanceId); + instanceIdMap_[asyncContext->instanceId].emplace_back(asyncContext); + return; + } + // make sure id is in map to indicate a pop-up window is showing + instanceIdMap_[asyncContext->instanceId] = {}; + } + StartUIExtension(asyncContext); +} + +void RequestGlobalSwitchAsyncInstanceControl::UpdateQueueData( + const std::shared_ptr& reqContext) +{ + if ((reqContext->errorCode != RET_SUCCESS) || !(reqContext->switchStatus)) { + LOGI(ATM_DOMAIN, ATM_TAG, "The queue data does not need to be updated."); + return; + } + + { + std::lock_guard lock(instanceIdMutex_); + int32_t id = reqContext->instanceId; + auto iter = instanceIdMap_.find(id); + if (iter == instanceIdMap_.end()) { + LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d not existed.", id); + return; + } + int32_t targetSwitchType = reqContext->switchType; + LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size()); + for (auto& asyncContext : iter->second) { + if (targetSwitchType == asyncContext->switchType) { + asyncContext->errorCode = reqContext->errorCode; + asyncContext->switchStatus = reqContext->switchStatus; + asyncContext->isDynamic = false; + } + } + } +} + +void RequestGlobalSwitchAsyncInstanceControl::ExecCallback(int32_t id) +{ + std::shared_ptr asyncContext = nullptr; + bool isDynamic = false; + { + std::lock_guard lock(instanceIdMutex_); + auto iter = instanceIdMap_.find(id); + if (iter == instanceIdMap_.end()) { + LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d not existed.", id); + return; + } + while (!iter->second.empty()) { + LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size()); + asyncContext = iter->second[0]; + iter->second.erase(iter->second.begin()); + CheckDynamicRequest(asyncContext, isDynamic); + if (isDynamic) { + break; + } + } + if (iter->second.empty()) { + LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map is empty", id); + instanceIdMap_.erase(id); + } + } + if (isDynamic) { + StartUIExtension(asyncContext); + } +} + +void RequestGlobalSwitchAsyncInstanceControl::CheckDynamicRequest( + std::shared_ptr& asyncContext, bool& isDynamic) +{ + isDynamic = asyncContext->isDynamic; + if (!isDynamic) { + LOGI(ATM_DOMAIN, ATM_TAG, "It does not need to request permission exsion"); + GlobalSwitchResultsCallbackUI( + TransferToJsErrorCode(asyncContext->errorCode), asyncContext->switchStatus, asyncContext); + return; + } +} + napi_value NapiRequestGlobalSwitch::RequestGlobalSwitch(napi_env env, napi_callback_info info) { LOGD(ATM_DOMAIN, ATM_TAG, "RequestGlobalSwitch begin."); @@ -461,8 +577,10 @@ void NapiRequestGlobalSwitch::RequestGlobalSwitchExecute(napi_env env, void* dat return; } + GetInstanceId(asyncContextHandle->asyncContextPtr); LOGI(ATM_DOMAIN, ATM_TAG, "Start to pop ui extension dialog"); - StartUIExtension(asyncContextHandle->asyncContextPtr); + + RequestGlobalSwitchAsyncInstanceControl::AddCallbackByInstanceId(asyncContextHandle->asyncContextPtr); if (asyncContextHandle->asyncContextPtr->result != JsErrorCode::JS_OK) { LOGW(ATM_DOMAIN, ATM_TAG, "Failed to pop uiextension dialog."); } diff --git a/frameworks/js/napi/accesstoken/src/napi_request_permission_on_setting.cpp b/frameworks/js/napi/accesstoken/src/napi_request_permission_on_setting.cpp index f252956596c37f87e71985a06cf01c2956320aae..b5267c4c12cb1de06546935299d68521463a8106 100644 --- a/frameworks/js/napi/accesstoken/src/napi_request_permission_on_setting.cpp +++ b/frameworks/js/napi/accesstoken/src/napi_request_permission_on_setting.cpp @@ -24,6 +24,9 @@ namespace OHOS { namespace Security { namespace AccessToken { +std::map>> + RequestOnSettingAsyncInstanceControl::instanceIdMap_; +std::mutex RequestOnSettingAsyncInstanceControl::instanceIdMutex_; namespace { const std::string PERMISSION_KEY = "ohos.user.setting.permission"; const std::string PERMISSION_RESULT_KEY = "ohos.user.setting.permission.result"; @@ -226,6 +229,8 @@ void PermissonOnSettingUICallback::ReleaseHandler(int32_t code) if (code == -1) { this->reqContext_->errorCode = code; } + RequestOnSettingAsyncInstanceControl::UpdateQueueData(this->reqContext_); + RequestOnSettingAsyncInstanceControl::ExecCallback(this->reqContext_->instanceId); PermissionResultsCallbackUI( TransferToJsErrorCode(this->reqContext_->errorCode), this->reqContext_->stateList, this->reqContext_); } @@ -382,6 +387,144 @@ static int32_t StartUIExtension(std::shared_ptr& asyncContext) +{ + auto task = [asyncContext]() { + Ace::UIContent* uiContent = GetUIContent(asyncContext); + if (uiContent == nullptr) { + LOGE(ATM_DOMAIN, ATM_TAG, "Get ui content failed!"); + return; + } + asyncContext->instanceId = uiContent->GetInstanceId(); + }; +#ifdef EVENTHANDLER_ENABLE + if (asyncContext->handler_ != nullptr) { + asyncContext->handler_->PostSyncTask(task, "AT:GetInstanceId"); + } else { + task(); + } +#else + task(); +#endif + LOGI(ATM_DOMAIN, ATM_TAG, "Instance id: %{public}d", asyncContext->instanceId); +} + +void RequestOnSettingAsyncInstanceControl::AddCallbackByInstanceId( + std::shared_ptr& asyncContext) +{ + LOGI(ATM_DOMAIN, ATM_TAG, "InstanceId: %{public}d", asyncContext->instanceId); + { + std::lock_guard lock(instanceIdMutex_); + auto iter = instanceIdMap_.find(asyncContext->instanceId); + // id is existed mean a pop window is showing, add context to waiting queue + if (iter != instanceIdMap_.end()) { + LOGI(ATM_DOMAIN, ATM_TAG, "InstanceId: %{public}d has existed.", asyncContext->instanceId); + instanceIdMap_[asyncContext->instanceId].emplace_back(asyncContext); + return; + } + // make sure id is in map to indicate a pop-up window is showing + instanceIdMap_[asyncContext->instanceId] = {}; + } + StartUIExtension(asyncContext); +} + +bool static CheckPermList(std::vector permList, std::vector tmpPermList) +{ + if (permList.size() != tmpPermList.size()) { + LOGI(ATM_DOMAIN, ATM_TAG, "Perm list size not equal, CurrentPermList size: %{public}zu.", tmpPermList.size()); + return false; + } + + for (const auto& item : permList) { + auto iter = std::find_if(tmpPermList.begin(), tmpPermList.end(), [item](const std::string& perm) { + return item == perm; + }); + if (iter == tmpPermList.end()) { + LOGI(ATM_DOMAIN, ATM_TAG, "Different permission lists."); + return false; + } + } + return true; +} + +void RequestOnSettingAsyncInstanceControl::UpdateQueueData( + const std::shared_ptr& reqContext) +{ + if (reqContext->errorCode != RET_SUCCESS) { + LOGI(ATM_DOMAIN, ATM_TAG, "The queue data does not need to be updated."); + return; + } + for (const int32_t item : reqContext->stateList) { + if (item != PERMISSION_GRANTED) { + LOGI(ATM_DOMAIN, ATM_TAG, "The queue data does not need to be updated"); + return; + } + } + + { + std::lock_guard lock(instanceIdMutex_); + int32_t id = reqContext->instanceId; + auto iter = instanceIdMap_.find(id); + if (iter == instanceIdMap_.end()) { + LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d not existed.", id); + return; + } + std::vector permList = reqContext->permissionList; + LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size()); + for (auto& asyncContext : iter->second) { + std::vector tmpPermList = asyncContext->permissionList; + + if (CheckPermList(permList, tmpPermList)) { + asyncContext->errorCode = reqContext->errorCode; + asyncContext->stateList = reqContext->stateList; + asyncContext->isDynamic = false; + } + } + } +} + +void RequestOnSettingAsyncInstanceControl::ExecCallback(int32_t id) +{ + std::shared_ptr asyncContext = nullptr; + bool isDynamic = false; + { + std::lock_guard lock(instanceIdMutex_); + auto iter = instanceIdMap_.find(id); + if (iter == instanceIdMap_.end()) { + LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d not existed.", id); + return; + } + while (!iter->second.empty()) { + LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map size: %{public}zu.", id, iter->second.size()); + asyncContext = iter->second[0]; + iter->second.erase(iter->second.begin()); + CheckDynamicRequest(asyncContext, isDynamic); + if (isDynamic) { + break; + } + } + if (iter->second.empty()) { + LOGI(ATM_DOMAIN, ATM_TAG, "Id: %{public}d, map is empty", id); + instanceIdMap_.erase(id); + } + } + if (isDynamic) { + StartUIExtension(asyncContext); + } +} + +void RequestOnSettingAsyncInstanceControl::CheckDynamicRequest( + std::shared_ptr& asyncContext, bool& isDynamic) +{ + isDynamic = asyncContext->isDynamic; + if (!isDynamic) { + LOGI(ATM_DOMAIN, ATM_TAG, "It does not need to request permission exsion"); + PermissionResultsCallbackUI( + TransferToJsErrorCode(asyncContext->errorCode), asyncContext->stateList, asyncContext); + return; + } +} + napi_value NapiRequestPermissionOnSetting::RequestPermissionOnSetting(napi_env env, napi_callback_info info) { LOGD(ATM_DOMAIN, ATM_TAG, "RequestPermissionOnSetting begin."); @@ -488,8 +631,10 @@ void NapiRequestPermissionOnSetting::RequestPermissionOnSettingExecute(napi_env return; } + GetInstanceId(asyncContextHandle->asyncContextPtr); LOGI(ATM_DOMAIN, ATM_TAG, "Start to pop ui extension dialog"); - StartUIExtension(asyncContextHandle->asyncContextPtr); + + RequestOnSettingAsyncInstanceControl::AddCallbackByInstanceId(asyncContextHandle->asyncContextPtr); if (asyncContextHandle->asyncContextPtr->result != JsErrorCode::JS_OK) { LOGW(ATM_DOMAIN, ATM_TAG, "Failed to pop uiextension dialog."); } diff --git a/interfaces/kits/js/napi/accesstoken/include/napi_request_global_switch_on_setting.h b/interfaces/kits/js/napi/accesstoken/include/napi_request_global_switch_on_setting.h index 76f9a1989e7af94161761bc02745b8c74cb4b133..ee549aabe1dc8db215f753e384764c640615cfca 100644 --- a/interfaces/kits/js/napi/accesstoken/include/napi_request_global_switch_on_setting.h +++ b/interfaces/kits/js/napi/accesstoken/include/napi_request_global_switch_on_setting.h @@ -47,6 +47,8 @@ struct RequestGlobalSwitchAsyncContext : public AtManagerAsyncWorkData { napi_value requestResult = nullptr; int32_t errorCode = -1; bool switchStatus = false; + int32_t instanceId = -1; + bool isDynamic = true; std::shared_ptr abilityContext; std::shared_ptr uiExtensionContext; bool uiAbilityFlag = false; @@ -66,6 +68,18 @@ struct RequestGlobalSwitchAsyncContextHandle { std::shared_ptr asyncContextPtr; }; +class RequestGlobalSwitchAsyncInstanceControl { + public: + static void AddCallbackByInstanceId(std::shared_ptr& asyncContext); + static void ExecCallback(int32_t id); + static void CheckDynamicRequest( + std::shared_ptr& asyncContext, bool& isDynamic); + static void UpdateQueueData(const std::shared_ptr& asyncContext); + private: + static std::map>> instanceIdMap_; + static std::mutex instanceIdMutex_; +}; + class SwitchOnSettingUICallback { public: explicit SwitchOnSettingUICallback(const std::shared_ptr& reqContext); diff --git a/interfaces/kits/js/napi/accesstoken/include/napi_request_permission_on_setting.h b/interfaces/kits/js/napi/accesstoken/include/napi_request_permission_on_setting.h index 7318e28393cce2f8144751b869221b6409c0f197..603f53fd2d857b79645dfbfdca9b19a2cb4304f8 100644 --- a/interfaces/kits/js/napi/accesstoken/include/napi_request_permission_on_setting.h +++ b/interfaces/kits/js/napi/accesstoken/include/napi_request_permission_on_setting.h @@ -38,6 +38,8 @@ struct RequestPermOnSettingAsyncContext : public AtManagerAsyncWorkData { PermissionGrantInfo info; int32_t resultCode = -1; + int32_t instanceId = -1; + bool isDynamic = true; std::vector permissionList; napi_value requestResult = nullptr; int32_t errorCode = -1; @@ -61,6 +63,18 @@ struct RequestOnSettingAsyncContextHandle { std::shared_ptr asyncContextPtr; }; +class RequestOnSettingAsyncInstanceControl { + public: + static void AddCallbackByInstanceId(std::shared_ptr& asyncContext); + static void ExecCallback(int32_t id); + static void CheckDynamicRequest( + std::shared_ptr& asyncContext, bool& isDynamic); + static void UpdateQueueData(const std::shared_ptr& asyncContext); + private: + static std::map>> instanceIdMap_; + static std::mutex instanceIdMutex_; +}; + class PermissonOnSettingUICallback { public: explicit PermissonOnSettingUICallback(const std::shared_ptr& reqContext);