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 "core/common/ai/ai_write_adapter.h"
17
18#include "array_wrapper.h"
19#include "bool_wrapper.h"
20#include "int_wrapper.h"
21#include "want.h"
22#include "want_params.h"
23#include "core/components_ng/layout/layout_property.h"
24#include "core/components_ng/pattern/text/span/span_string.h"
25#include "core/components_ng/pattern/ui_extension/session_wrapper.h"
26#include "core/components_ng/pattern/ui_extension/session_wrapper_factory.h"
27#include "core/components_ng/pattern/ui_extension/ui_extension_pattern.h"
28#include "core/components_ng/pattern/ui_extension/modal_ui_extension_proxy_impl.h"
29
30namespace OHOS::Ace {
31const std::pair<std::string, std::string> UI_ENTENSION_TYPE = {"ability.want.params.uiExtensionType", "sys/commonUI"};
32const std::wstring BOUNDARY_SYMBOLS = L",.?,。?!";
33const std::string API_VERSION = "apiVersion";
34const std::string RESULT_BUFFER = "resultBuffer";
35const std::string SHEET_DISMISS = "sheetDismiss";
36const std::string PROCESS_ID = "processId";
37const std::string MAX_CONTENT_LENGTH = "maxContentLength";
38const std::string FIRST_HANDLE_RECT = "firstHandleRect";
39const std::string SECOND_HANDLE_RECT = "secondHandleRect";
40const std::string IS_AI_SUPPORT_METADATA = "isAiSupport";
41const std::string SELECT_CONTENT_LENGTH = "selectContentLength";
42const std::string REQUEST_LONG_CONTENT = "requestLongContent";
43const std::string LONG_SENTENCE_BUFFER = "longSentenceBuffer";
44const std::string LONG_SELECT_START = "longSelectStart";
45const std::string LONG_SELECT_END = "longSelectEnd";
46const std::string KEY_PACKAGE_NAME = "keyPackageApp";
47const std::string START_COMPONONT_TYPE = "startComponentType";
48
49bool AIWriteAdapter::IsSentenceBoundary(const wchar_t value)
50{
51    for (wchar_t item: BOUNDARY_SYMBOLS) {
52        if (value == item) {
53            return true;
54        }
55    }
56    return false;
57}
58
59uint32_t AIWriteAdapter::GetSelectLengthOnlyText(const std::wstring& content)
60{
61    uint32_t length = 0;
62    for (uint32_t i = 0; i < content.length(); i++) {
63        if (content[i] != L' ' && content[i] != L'\n') {
64            length++;
65        }
66    }
67    return length;
68}
69
70void AIWriteAdapter::CloseModalUIExtension()
71{
72    TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "CloseModalUIExtension.");
73    auto context = pipelineContext_.Upgrade();
74    CHECK_NULL_VOID(context);
75    auto overlayManager = context->GetOverlayManager();
76    CHECK_NULL_VOID(overlayManager);
77    overlayManager->CloseModalUIExtension(sessionId_);
78    SetAIWrite(false);
79}
80
81void AIWriteAdapter::ShowModalUIExtension(const AIWriteInfo& info,
82    std::function<void(std::vector<uint8_t>&)> resultCallback)
83{
84    TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "ShowModalUIExtension.");
85    AAFwk::Want want;
86    SetWantParams(info, want);
87    Ace::ModalUIExtensionCallbacks callbacks;
88    BindModalUIExtensionCallback(callbacks, resultCallback);
89
90    auto context = pipelineContext_.Upgrade();
91    CHECK_NULL_VOID(context);
92    auto overlayManager = context->GetOverlayManager();
93    CHECK_NULL_VOID(overlayManager);
94    Ace::ModalUIExtensionConfig config;
95    sessionId_ = overlayManager->CreateModalUIExtension(want, callbacks, config);
96    aiWriteInfo_ = info;
97}
98
99void AIWriteAdapter::SetWantParams(const AIWriteInfo& info, AAFwk::Want& want)
100{
101    auto apiVersion = AceApplicationInfo::GetInstance().GetApiTargetVersion();
102    want.SetElementName(bundleName_, abilityName_);
103    want.SetParam(UI_ENTENSION_TYPE.first, UI_ENTENSION_TYPE.second);
104    want.SetParam(API_VERSION, static_cast<int>(apiVersion));
105    want.SetParam(PROCESS_ID, getpid());
106    want.SetParam(MAX_CONTENT_LENGTH, info.maxLength);
107    want.SetParam(SELECT_CONTENT_LENGTH, info.selectLength);
108    want.SetParam(FIRST_HANDLE_RECT, info.firstHandle);
109    want.SetParam(SECOND_HANDLE_RECT, info.secondHandle);
110    want.SetParam(KEY_PACKAGE_NAME, AceApplicationInfo::GetInstance().GetPackageName());
111    want.SetParam(START_COMPONONT_TYPE, info.componentType);
112}
113
114void AIWriteAdapter::BindModalUIExtensionCallback(
115    Ace::ModalUIExtensionCallbacks& callbacks, std::function<void(std::vector<uint8_t>&)> resultCallback)
116{
117    callbacks.onResult = [](int32_t code, const AAFwk::Want& want) {
118        TAG_LOGD(AceLogTag::ACE_UIEXTENSIONCOMPONENT, "UIExtension onResult, code: %{public}d", code);
119    };
120    callbacks.onDestroy = [weak = WeakClaim(this)]() {
121        TAG_LOGD(AceLogTag::ACE_UIEXTENSIONCOMPONENT, "UIExtension onDestroy.");
122        auto aiWriteAdapter = weak.Upgrade();
123        CHECK_NULL_VOID(aiWriteAdapter);
124        aiWriteAdapter->CloseModalUIExtension();
125    };
126    callbacks.onError = [weak = WeakClaim(this)](int32_t code, const std::string& name, const std::string& message) {
127        TAG_LOGE(AceLogTag::ACE_UIEXTENSIONCOMPONENT,
128            "UIExtension onError, code: %{public}d, name: %{public}s, message: %{public}s",
129            code, name.c_str(), message.c_str());
130        auto aiWriteAdapter = weak.Upgrade();
131        CHECK_NULL_VOID(aiWriteAdapter);
132        aiWriteAdapter->CloseModalUIExtension();
133    };
134    callbacks.onRelease = [](int32_t code) {
135        TAG_LOGD(AceLogTag::ACE_UIEXTENSIONCOMPONENT, "UIExtension onRelease, code: %{public}d", code);
136    };
137    callbacks.onRemoteReady = [weak = WeakClaim(this)](const std::shared_ptr<Ace::ModalUIExtensionProxy>& proxy) {
138        TAG_LOGD(AceLogTag::ACE_UIEXTENSIONCOMPONENT, "UIExtension onRemoteReady.");
139        auto aiWriteAdapter = weak.Upgrade();
140        CHECK_NULL_VOID(aiWriteAdapter);
141        aiWriteAdapter->SetModalUIExtensionProxy(proxy);
142    };
143    callbacks.onReceive = [weak = WeakClaim(this), cb = std::move(resultCallback)]
144        (const AAFwk::WantParams& wantParams) {
145        auto aiWriteAdapter = weak.Upgrade();
146        CHECK_NULL_VOID(aiWriteAdapter);
147        auto isSheetClose = false;
148        auto isRequest = false;
149        auto result = aiWriteAdapter->GetBufferParam(RESULT_BUFFER, wantParams);
150        isSheetClose = aiWriteAdapter->GetBoolParam(SHEET_DISMISS, wantParams);
151        isRequest = aiWriteAdapter->GetBoolParam(REQUEST_LONG_CONTENT, wantParams);
152        if (isRequest) {
153            aiWriteAdapter->SendData();
154            return;
155        }
156        if (cb && !result.empty()) {
157            cb(result);
158            return;
159        }
160        if (isSheetClose) {
161            aiWriteAdapter->CloseModalUIExtension();
162        }
163    };
164}
165
166void AIWriteAdapter::SendData()
167{
168    auto proxy = GetModalUIExtensionProxy();
169    AAFwk::WantParams wantParams;
170    SetArrayParam(wantParams, LONG_SENTENCE_BUFFER, aiWriteInfo_.sentenceBuffer);
171    wantParams.SetParam(LONG_SELECT_START, AAFwk::Integer::Box(aiWriteInfo_.start));
172    wantParams.SetParam(LONG_SELECT_END, AAFwk::Integer::Box(aiWriteInfo_.end));
173    proxy->SendData(wantParams);
174}
175
176void AIWriteAdapter::SetArrayParam(
177    AAFwk::WantParams& wantParams, const std::string& key, const std::vector<uint8_t>& value)
178{
179    std::vector<int> valueVec(value.size());
180    std::transform(value.begin(), value.end(), valueVec.begin(),
181        [](uint8_t x) { return static_cast<int>(x); });
182    size_t size = valueVec.size();
183    sptr<AAFwk::IArray> ao = new (std::nothrow) AAFwk::Array(size, AAFwk::g_IID_IInteger);
184    if (ao == nullptr) {
185        return;
186    }
187    for (size_t i = 0; i < size; i++) {
188        ao->Set(i, AAFwk::Integer::Box(value[i]));
189    }
190    wantParams.SetParam(key, ao);
191}
192
193std::vector<uint8_t> AIWriteAdapter::GetBufferParam(const std::string& key, const AAFwk::WantParams& wantParams)
194{
195    std::vector<uint8_t> array;
196    auto value = wantParams.GetParam(key);
197    AAFwk::IArray *ao = AAFwk::IArray::Query(value);
198    if (ao != nullptr && AAFwk::Array::IsIntegerArray(ao)) {
199        auto func = [&](AAFwk::IInterface *object) {
200            CHECK_NULL_VOID(object);
201            AAFwk::IInteger *value = AAFwk::IInteger::Query(object);
202            CHECK_NULL_VOID(value);
203            array.emplace_back(AAFwk::Integer::Unbox(value));
204        };
205        AAFwk::Array::ForEach(ao, func);
206    }
207    return array;
208}
209
210bool AIWriteAdapter::GetBoolParam(const std::string& key, const AAFwk::WantParams& wantParams)
211{
212    auto value = wantParams.GetParam(key);
213    AAFwk::IBoolean *bo = AAFwk::IBoolean::Query(value);
214    if (bo != nullptr) {
215        return AAFwk::Boolean::Unbox(bo);
216    }
217    return false;
218}
219}