1 /*
2 * Copyright (c) 2025 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 #define ABILITY_WANT_PARAMS_UIEXTENSIONTARGETTYPE "ability.want.params.uiExtensionTargetType"
16
17 #include "cj_picker.h"
18
19 #include "modal_ui_extension_config.h"
20 #include "ability.h"
21 #include "ui_extension_context.h"
22
23 namespace OHOS {
24 namespace CjPicker {
25
26 using namespace OHOS::Ace;
27
28 const int32_t ERR_OK = 0;
29 const int32_t ERR_INVALID_ARG = 13900020;
30 const int32_t ERR_INV = -1;
31
GetUIContextByContext(OHOS::AbilityRuntime::Context * context)32 static Ace::UIContent* GetUIContextByContext(OHOS::AbilityRuntime::Context* context)
33 {
34 auto contextsptr = context->shared_from_this();
35 auto abilityContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(contextsptr);
36 if (abilityContext == nullptr) {
37 auto uiExtensionContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(contextsptr);
38 if (uiExtensionContext == nullptr) {
39 HILOG_ERROR("[picker]: Fail to convert to abilityContext or uiExtensionContext");
40 return nullptr;
41 }
42 return uiExtensionContext->GetUIContent();
43 }
44 return abilityContext->GetUIContent();
45 }
46
StartCjPickerExtension(OHOS::AbilityRuntime::Context * context,WantHandle want,void (* cjCallback)(PickerResult))47 static int32_t StartCjPickerExtension(OHOS::AbilityRuntime::Context* context,
48 WantHandle want, void (*cjCallback)(PickerResult))
49 {
50 HILOG_INFO("[picker]: StartPickerExtension begin.");
51 Ace::UIContent *uiContent;
52 if (window_) {
53 HILOG_INFO("[picker] Will get uiContent by window.");
54 uiContent = window_->GetUIContent();
55 } else {
56 HILOG_INFO("[picker] Will get uiContent by context.");
57 uiContent = GetUIContextByContext(context);
58 }
59
60 if (uiContent == nullptr) {
61 HILOG_ERROR("[picker]: get uiContent failed");
62 return ERR_INVALID_ARG;
63 }
64 AAFwk::Want request = *reinterpret_cast<AAFwk::Want*>(want);
65
66 std::string targetType = request.GetStringParam("extType");
67 std::string pickerType;
68 if (request.GetParams().HasParam("pickerType")) {
69 pickerType = request.GetStringParam("pickerType");
70 }
71 request.SetParam(ABILITY_WANT_PARAMS_UIEXTENSIONTARGETTYPE, targetType);
72 auto pickerCallback = std::make_shared<CjPickerCallBack>();
73 auto callback = std::make_shared<CjModalUICallback>(uiContent, pickerCallback, cjCallback);
74 Ace::ModalUIExtensionCallbacks extensionCallback = {
75 .onRelease = std::bind(&CjModalUICallback::OnRelease, callback, std::placeholders::_1),
76 .onResult = std::bind(&CjModalUICallback::OnResultForModal, callback, std::placeholders::_1,
77 std::placeholders::_2),
78 .onReceive = std::bind(&CjModalUICallback::OnReceive, callback, std::placeholders::_1),
79 .onError = std::bind(&CjModalUICallback::OnError, callback, std::placeholders::_1, std::placeholders::_2,
80 std::placeholders::_3),
81 .onDestroy = std::bind(&CjModalUICallback::OnDestroy, callback),
82 };
83 Ace::ModalUIExtensionConfig config;
84 config.prohibitedRemoveByNavigation = false;
85 config.prohibitedRemoveByRouter = false;
86 HILOG_INFO("[picker]: will CreateModalUIExtension by extType: %{public}s, pickerType: %{public}s",
87 targetType.c_str(), pickerType.c_str());
88 int sessionId = uiContent->CreateModalUIExtension(request, extensionCallback, config);
89 if (sessionId == 0) {
90 HILOG_ERROR("[picker]: create modalUIExtension failed");
91 return ERR_INVALID_ARG;
92 }
93 callback->SetSessionId(sessionId);
94 return ERR_OK;
95 }
96
GetWindow(char * windowName,sptr<Rosen::Window> & window)97 static int32_t GetWindow(char* windowName, sptr<Rosen::Window> &window)
98 {
99 auto customWindow = Rosen::Window::Find(windowName);
100 if (!customWindow) {
101 HILOG_ERROR("[picker] Window find fail.");
102 return ERR_INV;
103 }
104 window = customWindow;
105 HILOG_INFO("[picker] Window found: %{public}s", windowName);
106 return ERR_OK;
107 }
108
MallocCString(const std::string & origin)109 static char* MallocCString(const std::string &origin)
110 {
111 if (origin.empty()) {
112 return nullptr;
113 }
114 auto length = origin.length() + 1;
115 char *res = static_cast<char *>(malloc(sizeof(char) * length));
116 if (res == nullptr) {
117 return nullptr;
118 }
119 return std::char_traits<char>::copy(res, origin.c_str(), length);
120 }
121
MallocStringVec(std::vector<std::string> & origin)122 static CArrString MallocStringVec(std::vector<std::string> &origin)
123 {
124 CArrString res{};
125 if (origin.empty()) {
126 return res;
127 }
128
129 size_t size = origin.size();
130 if (size == 0 || size > std::numeric_limits<size_t>::max() / sizeof(char *)) {
131 return res;
132 }
133 res.head = static_cast<char **>(malloc(sizeof(char *) * size));
134 if (res.head == nullptr) {
135 return res;
136 }
137 size_t i = 0;
138 for (; i < size; ++i) {
139 res.head[i] = MallocCString(origin[i]);
140 }
141 res.size = static_cast<int64_t>(i);
142
143 return res;
144 }
145
MakePickerResult(std::shared_ptr<CjPickerCallBack> pickerCallback)146 static PickerResult MakePickerResult(std::shared_ptr<CjPickerCallBack> pickerCallback)
147 {
148 PickerResult ret{};
149 ret.resultCode = pickerCallback->resultCode;
150 ret.userSuffixIndex = pickerCallback->want.GetIntParam("userSuffixIndex", -1);
151 ret.isOriginal = pickerCallback->want.GetBoolParam("isOriginal", false);
152 if (pickerCallback->want.GetParams().HasParam("ability.params.stream")) {
153 auto list = pickerCallback->want.GetStringArrayParam("ability.params.stream");
154 ret.ability_params_stream = MallocStringVec(list);
155 }
156 if (pickerCallback->want.GetParams().HasParam("uriArr")) {
157 auto list = pickerCallback->want.GetStringArrayParam("uriArr");
158 ret.uriArr = MallocStringVec(list);
159 }
160 if (pickerCallback->want.GetParams().HasParam("select-item-list")) {
161 auto list = pickerCallback->want.GetStringArrayParam("select-item-list");
162 ret.photoUris = MallocStringVec(list);
163 }
164 return ret;
165 }
166
167 extern "C" {
FfiOHOSFilePickerModalPicker(OHOS::AbilityRuntime::Context * context,WantHandle config,char * windowName,void (* callback)(PickerResult))168 int32_t FfiOHOSFilePickerModalPicker(OHOS::AbilityRuntime::Context* context,
169 WantHandle config, char* windowName, void (*callback)(PickerResult))
170 {
171 if (!context || !config) {
172 HILOG_ERROR("[picker] context or config is nullptr.");
173 return ERR_INVALID_ARG;
174 }
175 if (windowName) {
176 int32_t status = GetWindow(windowName, window_);
177 if (status != ERR_OK) {
178 return status;
179 }
180 }
181 return StartCjPickerExtension(context, config, callback);
182 }
183 }
184
CjModalUICallback(Ace::UIContent * uiContent,std::shared_ptr<CjPickerCallBack> pickerCallBack,void (* callback)(PickerResult))185 CjModalUICallback::CjModalUICallback(Ace::UIContent* uiContent,
186 std::shared_ptr<CjPickerCallBack> pickerCallBack, void (*callback)(PickerResult))
187 {
188 this->uiContent = uiContent;
189 this->pickerCallBack_ = pickerCallBack;
190 this->callback = CJLambda::Create(callback);
191 }
192
SetSessionId(int32_t sessionId)193 void CjModalUICallback::SetSessionId(int32_t sessionId)
194 {
195 this->sessionId_ = sessionId;
196 }
197
OnRelease(int32_t releaseCode)198 void CjModalUICallback::OnRelease(int32_t releaseCode)
199 {
200 HILOG_INFO("[picker] OnRelease enter. release code is %{public}d", releaseCode);
201 if (!pickerCallBack_) {
202 HILOG_ERROR("[picker] OnRelease error");
203 return;
204 }
205 this->uiContent->CloseModalUIExtension(this->sessionId_);
206 pickerCallBack_->ready = true;
207
208 auto ret = MakePickerResult(pickerCallBack_);
209 this->callback(ret);
210 if (window_) {
211 window_ = nullptr;
212 }
213 }
214
OnError(int32_t code,const std::string & name,const std::string & message)215 void CjModalUICallback::OnError(int32_t code, const std::string& name, const std::string& message)
216 {
217 HILOG_ERROR("[picker] OnError enter. errorCode=%{public}d, name=%{public}s, message=%{public}s",
218 code, name.c_str(), message.c_str());
219 this->uiContent->CloseModalUIExtension(this->sessionId_);
220 }
221
OnResultForModal(int32_t resultCode,const OHOS::AAFwk::Want & result)222 void CjModalUICallback::OnResultForModal(int32_t resultCode, const OHOS::AAFwk::Want &result)
223 {
224 HILOG_INFO("[picker] OnResultForModal enter. resultCode is %{public}d,", resultCode);
225 if (!pickerCallBack_) {
226 HILOG_ERROR("[picker] OnResultForModal error.");
227 return;
228 }
229 pickerCallBack_->resultCode = resultCode;
230 pickerCallBack_->want = result;
231 }
232
OnReceive(const OHOS::AAFwk::WantParams & request)233 void CjModalUICallback::OnReceive(const OHOS::AAFwk::WantParams &request)
234 {
235 HILOG_INFO("[picker] OnReceive enter.");
236 }
237
OnDestroy()238 void CjModalUICallback::OnDestroy()
239 {
240 HILOG_INFO("[picker] OnDestroy enter.");
241 }
242
243 } // namespace CjPicker
244 } // namespace OHOS