1 /*
2  * Copyright (c) 2021 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 "core/components/hyperlink/hyperlink_resources.h"
17 
18 namespace OHOS::Ace {
19 
20 const char HYPERLINK_COMPONENT_PARAM_EQUALS[] = "#HWJS-=-#";
21 const char HYPERLINK_COMPONENT_PARAM_BEGIN[] = "#HWJS-?-#";
22 const char HYPERLINK_COMPONENT_METHOD[] = "method";
23 const char HYPERLINK_STARTABILITY[] = "startAbility";
24 const char HYPERLINK_URI[] = "url";
25 const char HYPERLINK_PARAM[] = "hyperlink";
26 const char HYPER_CREATE_PARAM[] = "hyperlink#HWJS-=-#startAbility";
27 
~HyperlinkResources()28 HyperlinkResources::~HyperlinkResources()
29 {
30     ReleasePluginResource();
31 }
32 
MakeResourceHash() const33 std::string HyperlinkResources::MakeResourceHash() const
34 {
35     std::stringstream hashCode;
36     hashCode << HYPERLINK_PARAM << "@" << id_;
37     return hashCode.str();
38 }
39 
MakeMethodHash(const std::string & method) const40 std::string HyperlinkResources::MakeMethodHash(const std::string& method) const
41 {
42     // method hash is hyperlink@(id)method#HWJS-=-#(method)#HWJS-?-#
43     std::string methodHash = MakeResourceHash();
44     methodHash += std::string(HYPERLINK_COMPONENT_METHOD);
45     methodHash += std::string(HYPERLINK_COMPONENT_PARAM_EQUALS);
46     methodHash += method;
47     methodHash += std::string(HYPERLINK_COMPONENT_PARAM_BEGIN);
48     return methodHash;
49 }
50 
CallResRegisterMethod(const std::string & method,const std::string & param)51 std::string HyperlinkResources::CallResRegisterMethod(const std::string& method, const std::string& param)
52 {
53     if (method.empty()) {
54         return "";
55     }
56 
57     auto context = context_.Upgrade();
58     if (!context) {
59         LOGE("fail to get context to call res register method");
60         return "";
61     }
62 
63     auto resRegister = context->GetPlatformResRegister();
64     if (id_ == INVALID_ID) {
65         LOGE("fail to get a valid id");
66         return "";
67     }
68     auto platformTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::PLATFORM);
69     auto weakRes = AceType::WeakClaim(AceType::RawPtr(resRegister));
70 
71     platformTaskExecutor.PostTask([method, param, weakRes] {
72         auto resRegister = weakRes.Upgrade();
73         if (resRegister != nullptr) {
74             std::string result;
75             resRegister->OnMethodCall(method, param, result);
76         }
77     }, "ArkUIHyperlinkCallResRegisterMethod");
78     return "";
79 }
80 
StartAbility(const std::string & address)81 void HyperlinkResources::StartAbility(const std::string& address)
82 {
83     std::string startAbilityMethod = MakeMethodHash(HYPERLINK_STARTABILITY);
84     std::stringstream paramStream;
85     paramStream << HYPERLINK_URI << HYPERLINK_COMPONENT_PARAM_EQUALS << address;
86     std::string param = paramStream.str();
87     CallResRegisterMethod(startAbilityMethod, param);
88 }
89 
CreatePlatformResource(const WeakPtr<PipelineContext> & context)90 void HyperlinkResources::CreatePlatformResource(const WeakPtr<PipelineContext>& context)
91 {
92     context_ = context;
93     CreatePluginResource(context);
94 }
95 
CreatePluginResource(const WeakPtr<PipelineContext> & context)96 void HyperlinkResources::CreatePluginResource(const WeakPtr<PipelineContext>& context)
97 {
98     // create AceHyperlinkOhos with id
99     auto pipelineContext = context.Upgrade();
100     if (!pipelineContext) {
101         return;
102     }
103     context_ = context;
104     auto platformTaskExecutor =
105         SingleTaskExecutor::Make(pipelineContext->GetTaskExecutor(), TaskExecutor::TaskType::PLATFORM);
106     auto resRegister = pipelineContext->GetPlatformResRegister();
107     auto weakRes = AceType::WeakClaim(AceType::RawPtr(resRegister));
108     platformTaskExecutor.PostTask([weak = WeakClaim(this), weakRes] {
109         auto hyperlinkResource = weak.Upgrade();
110         if (!hyperlinkResource) {
111             return;
112         }
113         auto resRegister = weakRes.Upgrade();
114         if (!resRegister) {
115             return;
116         }
117         hyperlinkResource->id_ = resRegister->CreateResource(HYPERLINK_PARAM, HYPER_CREATE_PARAM);
118     }, "ArkUIHyperlinkCreatePluginResource");
119 }
120 
ReleasePluginResource()121 void HyperlinkResources::ReleasePluginResource()
122 {
123     // release AceHyperlinkOhos by id
124     auto context = context_.Upgrade();
125     if (!context) {
126         LOGE("fail to release resource due to context is null");
127         return;
128     }
129     auto resRegister = context->GetPlatformResRegister();
130     auto platformTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::PLATFORM);
131     auto weakRes = AceType::WeakClaim(AceType::RawPtr(resRegister));
132     hash_ = MakeResourceHash();
133     auto releaseTask = [id = id_, hash = hash_, weakRes] {
134         if (id == INVALID_ID) {
135             LOGW("ability component resource has released");
136             return;
137         }
138 
139         auto resRegister = weakRes.Upgrade();
140         if (resRegister) {
141             resRegister->ReleaseResource(hash);
142         }
143     };
144     if (platformTaskExecutor.IsRunOnCurrentThread()) {
145         releaseTask();
146     } else {
147         platformTaskExecutor.PostTask(releaseTask, "ArkUIHyperlinkReleasePluginResource");
148     }
149 }
150 
151 } // namespace OHOS::Ace
152