Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qohosqpafunctionsimpl.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtCore/private/qnapi_p.h>
5#include <QtCore/private/qohoscommon_p.h>
6#include <qohosjsenv_p.h>
7#include <QtCore/qobject.h>
8#include <QtCore/qscopeguard.h>
9#include <QtGui/private/qguiapplication_p.h>
10#include <QtGui/qcolor.h>
11#include <QtGui/qimage.h>
12#include <QtGui/qscreen.h>
13#include <QtGui/qwindow.h>
14#include <algorithm>
15#include <chrono>
16#include <filemanagement/file_uri/oh_file_uri.h>
17#include <filemanagement/fileshare/oh_file_share.h>
18#include <functional>
19#include <info/application_target_sdk_version.h>
20#include <memory>
21#include <qohosapppermissions_p.h>
22#include <qohosenums.h>
23#include <qohosjsmain.h>
24#include <qohosjsutils.h>
25#include <qohospixelmapconversions.h>
26#include <qohosplatformclipboard.h>
27#include <qohosplatformintegration.h>
28#include <qohosplatformservices.h>
29#include <qohosplatformwindow.h>
30#include <qohosplugincore.h>
31#include <qohosqpafunctions_p.h>
32#include <qohossettings.h>
33#include <qohossharekit.h>
34#include <qohosudmfconversions.h>
35#include <qohosutils.h>
36#include <qohoswindowmanager.h>
37#include <qohoswindowproperty.h>
38#include <render/qwindowproxyregistry.h>
39#include <signal.h>
40#include <thread>
41#include <unistd.h>
42#include <unordered_map>
43#include <vector>
44
45using namespace std::chrono_literals;
46
47QT_BEGIN_NAMESPACE
48
49namespace QtOhos {
50
51namespace {
52
53const QOhosPropertyDescriptor<QOhosQpaFunctions::AudioStreamUsage> audioStreamUsageProperty{};
54
55QOhosOptional<QOhosQpaFunctions::WantInfo::LaunchReason> tryMapOhosLaunchReasonToWantInfoEnum(
56 enums::ohos::app::ability::AbilityConstant::LaunchReason ohosLaunchReason)
57{
58 using OhosLaunchReason = enums::ohos::app::ability::AbilityConstant::LaunchReason;
59 using WantInfo = QOhosQpaFunctions::WantInfo;
60
61 switch (ohosLaunchReason) {
62 case OhosLaunchReason::START_ABILITY:
63 return makeQOhosOptional(WantInfo::LaunchReason::START_ABILITY);
64 case OhosLaunchReason::CONTINUATION:
65 return makeQOhosOptional(WantInfo::LaunchReason::CONTINUATION);
66 case OhosLaunchReason::PREPARE_CONTINUATION:
67 return makeQOhosOptional(WantInfo::LaunchReason::PREPARE_CONTINUATION);
68 case OhosLaunchReason::PRELOAD:
69 return makeQOhosOptional(WantInfo::LaunchReason::PRELOAD);
70 case OhosLaunchReason::UNKNOWN:
71 case OhosLaunchReason::CALL:
72 case OhosLaunchReason::APP_RECOVERY:
73 case OhosLaunchReason::SHARE:
74 case OhosLaunchReason::AUTO_STARTUP:
75 case OhosLaunchReason::INSIGHT_INTENT:
76 return makeQOhosOptional(WantInfo::LaunchReason::UNKNOWN);
77 }
78
79 return {};
80}
81
82QOhosQpaFunctions::WantInfo::LaunchReason mapJsLaunchReasonToWantInfoEnumWithFallback(
83 QtOhos::JsState &jsState, QNapi::Number jsLaunchReason)
84{
85 auto optLaunchReasonJsEnum =
86 jsState.tryMapOhosEnumFromJs<enums::ohos::app::ability::AbilityConstant::LaunchReason>(jsLaunchReason);
87 auto optLaunchReason =
88 optLaunchReasonJsEnum.has_value()
89 ? tryMapOhosLaunchReasonToWantInfoEnum(optLaunchReasonJsEnum.value())
90 : makeEmptyQOhosOptional();
91 return optLaunchReason.value_or(QOhosQpaFunctions::WantInfo::LaunchReason::UNKNOWN);
92}
93
94Q_NORETURN void killCurrentProcess()
95{
96 ::kill(getpid(), SIGKILL);
97 std::abort();
98}
99
100QOhosOptional<QOhosAbilityOnContinueResult> tryMapAbilityOnContinueResponseStatusToOhos(
102{
103 using AbilityOnContinueResponseStatus = QOhosQpaFunctions::AbilityOnContinueResponseStatus;
104
105 switch (status) {
106 case AbilityOnContinueResponseStatus::Agree:
107 return makeQOhosOptional(QOhosAbilityOnContinueResult::AGREE);
108 case AbilityOnContinueResponseStatus::Reject:
109 return makeQOhosOptional(QOhosAbilityOnContinueResult::REJECT);
110 case AbilityOnContinueResponseStatus::Mismatch:
111 return makeQOhosOptional(QOhosAbilityOnContinueResult::MISMATCH);
112 }
113 return {};
114}
115
116QOhosOptional<enums::ohos::app::ability::AbilityConstant::WindowMode> tryMapWindowModeToOhosOrLogWarning(
118{
119 namespace AbilityConstant = enums::ohos::app::ability::AbilityConstant;
120 using StartOptions = QOhosQpaFunctions::StartOptions;
121
122 switch (windowMode) {
124 return makeQOhosOptional(AbilityConstant::WindowMode::WINDOW_MODE_SPLIT_PRIMARY);
126 return makeQOhosOptional(AbilityConstant::WindowMode::WINDOW_MODE_SPLIT_SECONDARY);
128 return makeQOhosOptional(AbilityConstant::WindowMode::WINDOW_MODE_FULLSCREEN);
129 }
130
131 qCWarning(QtForOhos, "%s: got illegal WindowMode: %d", Q_FUNC_INFO, static_cast<int>(windowMode));
132
133 return {};
134}
135
136QOhosOptional<enums::ohos::app::ability::contextConstant::ProcessMode> tryMapProcessModeToOhosOrLogWarning(
138{
139 namespace contextConstant = enums::ohos::app::ability::contextConstant;
140 using StartOptions = QOhosQpaFunctions::StartOptions;
141
142 switch (processMode) {
144 return makeQOhosOptional(contextConstant::ProcessMode::NEW_PROCESS_ATTACH_TO_PARENT);
146 return makeQOhosOptional(contextConstant::ProcessMode::NEW_PROCESS_ATTACH_TO_STATUS_BAR_ITEM);
147 }
148
149 qCWarning(QtForOhos, "%s: got illegal ProcessMode: %d", Q_FUNC_INFO, static_cast<int>(processMode));
150
151 return {};
152}
153
154QOhosOptional<enums::ohos::app::ability::contextConstant::StartupVisibility> tryMapStartupVisibilityToOhosOrLogWarning(
156{
157 namespace contextConstant = enums::ohos::app::ability::contextConstant;
158 using StartOptions = QOhosQpaFunctions::StartOptions;
159
160 switch (startupVisibility) {
161 case StartOptions::StartupVisibility::STARTUP_HIDE:
162 return makeQOhosOptional(contextConstant::StartupVisibility::STARTUP_HIDE);
163 case StartOptions::StartupVisibility::STARTUP_SHOW:
164 return makeQOhosOptional(contextConstant::StartupVisibility::STARTUP_SHOW);
165 }
166
167 qCWarning(QtForOhos, "%s: got illegal StartupVisibility: %d", Q_FUNC_INFO, static_cast<int>(startupVisibility));
168
169 return {};
170}
171
172QOhosOptional<enums::ohos::bundle::bundleManager::SupportWindowMode> tryMapSupportWindowModeToOhosOrLogWarning(
174{
175 namespace bundleManager = enums::ohos::bundle::bundleManager;
176 using StartOptions = QOhosQpaFunctions::StartOptions;
177
178 switch (supportWindowMode) {
179 case StartOptions::SupportWindowMode::FULL_SCREEN:
180 return makeQOhosOptional(bundleManager::SupportWindowMode::FULL_SCREEN);
181 case StartOptions::SupportWindowMode::SPLIT:
182 return makeQOhosOptional(bundleManager::SupportWindowMode::SPLIT);
183 case StartOptions::SupportWindowMode::FLOATING:
184 return makeQOhosOptional(bundleManager::SupportWindowMode::FLOATING);
185 }
186
187 qCWarning(QtForOhos, "%s: got illegal SupportWindowMode: %d", Q_FUNC_INFO, static_cast<int>(supportWindowMode));
188
189 return {};
190}
191
192QNapi::Array mapSupportWindowModesToJsEnumsArray(
193 QtOhos::JsState &jsState, const QList<QOhosQpaFunctions::StartOptions::SupportWindowMode> &supportWindowModes)
194{
195 std::vector<QNapi::ValueWrapper> jsSupportWindowModes;
196 for (auto supportWindowMode : supportWindowModes) {
197 auto optOhosSupportWindowMode = tryMapSupportWindowModeToOhosOrLogWarning(supportWindowMode);
198 if (optOhosSupportWindowMode.has_value())
199 jsSupportWindowModes.push_back(jsState.mapOhosEnumToJs(optOhosSupportWindowMode.value()));
200 }
201
202 return QNapi::makeArray(jsState.env(), jsSupportWindowModes);
203}
204
205QNapi::Object makeJsCompletionHandler(
206 QtOhos::JsState &jsState, std::shared_ptr<QOhosConsumer<bool, QJsonObject, QString>> qtThreadCompletionHandler)
207{
208 auto makeCompletionCallback = [qtThreadCompletionHandler](bool requestSuccess) {
209 return [qtThreadCompletionHandler, requestSuccess](const QNapi::CallbackInfo &cbInfo) {
210 QNapi::Object elementNameObj;
211 QNapi::String messageValue;
212 cbInfo.getLeadingArgs(Q_FUNC_INFO, elementNameObj, messageValue);
213
214 const QJsonObject elementName = QOhosJsEnv::fromNapiValue<QJsonObject>(elementNameObj);
215 const QString message = QString::fromStdString(messageValue);
216
217 QtOhos::invokeInQtThread(
218 [qtThreadCompletionHandler, requestSuccess, elementName, message]() {
219 (*qtThreadCompletionHandler)(requestSuccess, elementName, message);
220 });
221 };
222 };
223
224 return QNapi::makeObject(
225 jsState.env(),
226 {
227 {"onRequestSuccess", makeCompletionCallback(true)},
228 {"onRequestFailure", makeCompletionCallback(false)},
229 });
230}
231
232using OhosConfigurationColorMode = QtOhos::enums::ohos::app::ability::ConfigurationConstant::ColorMode;
233
234QNapi::Object convertStartOptionsToNapiObject(
235 QtOhos::JsState &jsState, const QOhosQpaFunctions::StartOptions &opts)
236{
237 auto *env = jsState.env();
238 auto napiOptions = QNapi::Object::New(env);
239
240 auto optOhosWindowMode = qAndThen(opts.windowMode, &tryMapWindowModeToOhosOrLogWarning);
241 if (optOhosWindowMode.has_value())
242 napiOptions.set("windowMode", jsState.mapOhosEnumToJs(optOhosWindowMode.value()));
243 if (opts.displayId.has_value())
244 napiOptions.set("displayId", opts.displayId.value());
245 if (opts.withAnimation.has_value())
246 napiOptions.set("withAnimation", opts.withAnimation.value());
247 if (opts.windowLeft.has_value())
248 napiOptions.set("windowLeft", opts.windowLeft.value());
249 if (opts.windowTop.has_value())
250 napiOptions.set("windowTop", opts.windowTop.value());
251 if (opts.windowWidth.has_value())
252 napiOptions.set("windowWidth", opts.windowWidth.value());
253 if (opts.windowHeight.has_value())
254 napiOptions.set("windowHeight", opts.windowHeight.value());
255 auto optOhosProcessMode = qAndThen(opts.processMode, &tryMapProcessModeToOhosOrLogWarning);
256 if (optOhosProcessMode.has_value())
257 napiOptions.set("processMode", jsState.mapOhosEnumToJs(optOhosProcessMode.value()));
258 auto optOhosStartupVisibility = qAndThen(opts.startupVisibility, &tryMapStartupVisibilityToOhosOrLogWarning);
259 if (optOhosStartupVisibility.has_value())
260 napiOptions.set("startupVisibility", jsState.mapOhosEnumToJs(optOhosStartupVisibility.value()));
261 if (opts.windowIcon.has_value()) {
262 auto windowIcon = opts.windowIcon.value().value<QImage>();
263 if (!windowIcon.isNull())
264 napiOptions.set("startWindowIcon", createNapiPixelMapFromQImage(jsState, windowIcon));
265 }
266 if (opts.windowBackgroundColorHex.has_value())
267 napiOptions.set("startWindowBackgroundColor", opts.windowBackgroundColorHex.value().toStdString());
268 if (opts.supportWindowModes.has_value()) {
269 auto jsSupportWindowModes = mapSupportWindowModesToJsEnumsArray(jsState, opts.supportWindowModes.value());
270 if (jsSupportWindowModes.Length() != 0)
271 napiOptions.set("supportWindowModes", jsSupportWindowModes);
272 else
273 qCWarning(QtForOhos, "%s: OHOS doesn't support empty supportWindowModes, skipping", Q_FUNC_INFO);
274 }
275 if (opts.minWindowWidth.has_value())
276 napiOptions.set("minWindowWidth", opts.minWindowWidth.value());
277 if (opts.minWindowHeight.has_value())
278 napiOptions.set("minWindowHeight", opts.minWindowHeight.value());
279 if (opts.maxWindowWidth.has_value())
280 napiOptions.set("maxWindowWidth", opts.maxWindowWidth.value());
281 if (opts.maxWindowHeight.has_value())
282 napiOptions.set("maxWindowHeight", opts.maxWindowHeight.value());
283 if (opts.optCompletionHandler)
284 napiOptions.set("completionHandler", makeJsCompletionHandler(jsState, opts.optCompletionHandler));
285 if (opts.hideStartWindow.has_value())
286 napiOptions.set("hideStartWindow", opts.hideStartWindow.value());
287 if (opts.windowCreateParams.has_value()) {
288 const auto &windowCreateParams = opts.windowCreateParams.value();
289 std::vector<std::pair<std::string, QNapi::ValueWrapper>> windowCreateParamsProps;
290 if (windowCreateParams.setWindowFadeInOutAnimation) {
291 windowCreateParamsProps.emplace_back(
292 "animationParams",
293 QNapi::makeObject(
294 env,
295 {
296 {
297 "type",
298 jsState.mapOhosEnumToJs(
299 enums::ohos::window::AnimationType::FADE_IN_OUT),
300 }
301 }));
302 }
303 napiOptions.set("windowCreateParams", QNapi::makeObject(env, windowCreateParamsProps));
304 }
305
306 return napiOptions;
307}
308
309std::shared_ptr<void> registerAppContextEnvironmentCallback(
310 QtOhos::JsState &jsState, QNapi::Object environmentCallback)
311{
312 auto appContextRefPtr = QtOhos::moveToSharedPtr(
313 QNapi::Reference<>::makePersistentFrom(
314 jsState.defaultQAbilityPeer()->qAbility().eval<QNapi::Object>(
315 "context.getApplicationContext()")));
316
317 double environmentCallbackId = appContextRefPtr->call<QNapi::Number>(
318 "on",
319 {"environment", environmentCallback});
320
321 return std::shared_ptr<void>(
322 nullptr,
323 [environmentCallbackId, appContextRefPtr](auto) {
325 [&](QtOhos::JsState &) {
326 auto appContextRef = std::move(*appContextRefPtr);
327 appContextRef.call(
328 "off",
329 {"environment", environmentCallbackId});
330 },
331 Q_FUNC_INFO);
332 });
333}
334
335std::shared_ptr<void> registerAppConfigurationUpdateListener(
336 QtOhos::JsState &jsState, std::function<void(QtOhos::JsState &, QNapi::Object)> updateListener)
337{
338 return registerAppContextEnvironmentCallback(
339 jsState,
340 QNapi::makeObject(
341 jsState.env(),
342 {
343 {
344 "onConfigurationUpdated",
345 [updateListener = std::move(updateListener)](const QtOhos::CallbackInfo &cbInfo) {
346 auto config = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
347 updateListener(cbInfo.jsState(), config);
348 }
349 },
350 }));
351}
352
353OhosConfigurationColorMode mapOhosConfigurationColorModeFromJs(QtOhos::JsState &jsState, QNapi::Number colorModeJsEnum)
354{
355 constexpr auto fallbackColorMode = OhosConfigurationColorMode::COLOR_MODE_NOT_SET;
356 auto optColorMode = jsState.tryMapOhosEnumFromJs<OhosConfigurationColorMode>(colorModeJsEnum);
357 return optColorMode.value_or(fallbackColorMode);
358};
359
360void setOhosConfigColorMode(OhosConfigurationColorMode colorMode)
361{
363 qCWarning(QtForOhos, "%s: cannot set a color mode in 'no UI child mode'", Q_FUNC_INFO);
364 return;
365 }
366
368 [&](QtOhos::JsState &jsState) {
369 auto qAbility = jsState.defaultQAbilityPeer()->qAbility();
370 const auto jsColorMode = jsState.mapOhosEnumToJs(colorMode);
371 qAbility.call("context.getApplicationContext().setColorMode", {jsColorMode});
372 },
373 Q_FUNC_INFO);
374}
375
376template<typename ConfigValue>
377QOhosSupplier<ConfigValue> makeOhosConfigValueDataSource(
378 std::function<ConfigValue(QtOhos::JsState &)> initValueSupplier,
379 std::function<ConfigValue(QtOhos::JsState &, const QNapi::Object &)> valueFetcher,
380 QOhosConsumer<ConfigValue> valueChangedHandler)
381{
382 return QtOhos::makeDataSource<ConfigValue>(
383 std::move(initValueSupplier),
384 [valueFetcher = std::move(valueFetcher)](QtOhos::JsState &jsState, QOhosConsumer<ConfigValue> valueUpdatesConsumer) mutable {
385 return registerAppConfigurationUpdateListener(
386 jsState,
387 [valueFetcher = std::move(valueFetcher), valueUpdatesConsumer = std::move(valueUpdatesConsumer)](QtOhos::JsState &jsState, QNapi::Object config) {
388 valueUpdatesConsumer(valueFetcher(jsState, config));
389 });
390 },
391 std::move(valueChangedHandler),
392 Q_FUNC_INFO);
393}
394
395QOhosSupplier<OhosConfigurationColorMode> makeOhosConfigColorModeDataSource(
396 QOhosConsumer<OhosConfigurationColorMode> valueChangedHandler)
397{
398 return makeOhosConfigValueDataSource<OhosConfigurationColorMode>(
399 [](QtOhos::JsState &jsState) {
400 return mapOhosConfigurationColorModeFromJs(
401 jsState, jsState.defaultQAbilityPeer()->qAbility().eval<QNapi::Number>("context.config.colorMode"));
402 },
403 [](QtOhos::JsState &jsState, const QNapi::Object &config) {
404 return mapOhosConfigurationColorModeFromJs(jsState, config.get<QNapi::Number>("colorMode"));
405 },
406 std::move(valueChangedHandler));
407}
408
409QOhosOptional<bool> mapOhosConfigurationColorModeToDarkModeFlag(OhosConfigurationColorMode colorMode)
410{
411 switch (colorMode) {
412 case OhosConfigurationColorMode::COLOR_MODE_NOT_SET:
414 case OhosConfigurationColorMode::COLOR_MODE_LIGHT:
415 return makeQOhosOptional(false);
416 case OhosConfigurationColorMode::COLOR_MODE_DARK:
417 return makeQOhosOptional(true);
418 }
419
421}
422
423std::shared_ptr<char> makeSharedNullTerminatedString(std::string str)
424{
425 auto sharedStrData = QtOhos::moveToSharedPtr(std::move(str) + '\0');
426 return std::shared_ptr<char>(sharedStrData, &sharedStrData->front());
427}
428
429std::shared_ptr<char> makeSharedNullTerminatedString(const char *str)
430{
431 return makeSharedNullTerminatedString(std::string(str != nullptr ? str : ""));
432}
433
434template<typename ConvFunc>
435std::string callOhFileUriConversionFunc(
436 ConvFunc convFunc, const std::string &input)
437{
438 char *outputPtr = nullptr;
439 auto outputPtrGuard = qScopeGuard(std::bind(::free, outputPtr));
440 auto convFuncRetVal = convFunc(input.c_str(), input.size(), &outputPtr);
441
442 std::string outputString;
443 if (convFuncRetVal == ::FileManagement_ErrCode::ERR_OK && outputPtr != nullptr) {
444 outputString = outputPtr;
445 } else {
446 qOhosPrintfWarning(
447 "OH FileUri conversion function '%s' failed for input '%s', retval: %d",
448 convFunc.name(), input.c_str(), static_cast<int>(convFuncRetVal));
449 }
450
451 return outputString;
452}
453
454std::string mapPathToOhosUriInJsThread(const std::string &path)
455{
456 return callOhFileUriConversionFunc(Q_OHOS_NAMED_FUNC(::OH_FileUri_GetUriFromPath), path);
457}
458
459std::string mapOhosFileUriToPathInJsThread(const std::string &ohosFileUri)
460{
461 return callOhFileUriConversionFunc(Q_OHOS_NAMED_FUNC(::OH_FileUri_GetPathFromUri), ohosFileUri);
462}
463
464std::shared_ptr<::FileShare_PolicyInfo> makeFileSharePolicyInfo(
465 std::string uri, unsigned operationMode)
466{
467 auto sharedUri = makeSharedNullTerminatedString(std::move(uri));
468
469 auto policyInfo = QtOhos::moveToSharedPtr(
470 ::FileShare_PolicyInfo{
471 .uri = sharedUri.get(),
472 .length = static_cast<unsigned>(std::strlen(sharedUri.get())),
473 .operationMode = operationMode,
474 });
475
476 return QtOhos::makeSharedPtrWithAttachedExtraData(
477 policyInfo, sharedUri);
478}
479
480std::vector<std::shared_ptr<::FileShare_PolicyInfo>> convertToFileSharePolicyInfos(
481 const QList<QOhosQpaFunctions::FileShare::PolicyInfo> &policyInfos)
482{
483 std::vector<std::shared_ptr<::FileShare_PolicyInfo>> fileSharePolicies;
484
485 for (const auto &policyInfo : policyInfos) {
486 unsigned ohosOperationModes = 0;
487 for (auto operationMode : policyInfo.operationModes)
488 ohosOperationModes |= static_cast<unsigned>(operationMode);
489 fileSharePolicies.push_back(
490 makeFileSharePolicyInfo(
491 mapPathToOhosUriInJsThread(policyInfo.path.toStdString()),
492 ohosOperationModes));
493 }
494
495 return fileSharePolicies;
496}
497
498std::shared_ptr<::FileShare_PolicyErrorResult> makeFileSharePolicyErrorResultFromRawStruct(
499 const ::FileShare_PolicyErrorResult &inputStruct)
500{
501 auto sharedUri = makeSharedNullTerminatedString(inputStruct.uri);
502 auto sharedMessage = makeSharedNullTerminatedString(inputStruct.message);
503
504 auto policyErrorResult = QtOhos::moveToSharedPtr(
505 ::FileShare_PolicyErrorResult{
506 .uri = sharedUri.get(),
507 .code = inputStruct.code,
508 .message = sharedMessage.get(),
509 });
510
511 return QtOhos::makeSharedPtrWithAttachedExtraData(
512 policyErrorResult,
513 QtOhos::moveToSharedPtr(std::make_tuple(sharedUri, sharedMessage)));
514};
515
516std::vector<::FileShare_PolicyInfo> makePoliciesRawVectorView(
517 const std::vector<std::shared_ptr<::FileShare_PolicyInfo>> &policies)
518{
519 std::vector<::FileShare_PolicyInfo> rawVectorView;
520 for (const auto &policyPtr : policies)
521 rawVectorView.push_back(*policyPtr);
522
523 return rawVectorView;
524}
525
526template<typename PermissionActionFunc>
527::FileManagement_ErrCode callFileSharePermissionActionFunc(
528 PermissionActionFunc permissionActionFunc,
529 const std::vector<std::shared_ptr<::FileShare_PolicyInfo>> &policies,
530 std::vector<std::shared_ptr<::FileShare_PolicyErrorResult>> &outResult)
531{
532 auto policiesRawVectorView = makePoliciesRawVectorView(policies);
533 ::FileShare_PolicyErrorResult *resultParam = nullptr;
534 unsigned resultNumParam = 0;
535 auto resultParamReleaseGuard = qScopeGuard(
536 [&]() {
537 if (resultParam != nullptr && resultNumParam != 0)
538 ::OH_FileShare_ReleasePolicyErrorResult(resultParam, resultNumParam);
539 });
540
541 auto errCode = permissionActionFunc(
542 policiesRawVectorView.data(), policiesRawVectorView.size(),
543 &resultParam, &resultNumParam);
544
545 outResult.clear();
546 if (resultParam != nullptr) {
547 for (unsigned i = 0; i < resultNumParam; ++i) {
548 outResult.push_back(
549 makeFileSharePolicyErrorResultFromRawStruct(resultParam[i]));
550 }
551 }
552
553 return errCode;
554}
555
556::FileManagement_ErrCode fileShareCheckPersistentPermission(
557 const std::vector<std::shared_ptr<::FileShare_PolicyInfo>> &policies,
558 std::vector<bool> &outResult)
559{
560 auto policiesRawVectorView = makePoliciesRawVectorView(policies);
561 bool *resultParam = nullptr;
562 auto resultParamReleaseGuard = qScopeGuard(
563 [&]() {
564 ::free(resultParam);
565 });
566 unsigned resultNumParam = 0;
567
568 auto errCode = ::OH_FileShare_CheckPersistentPermission(
569 policiesRawVectorView.data(), policiesRawVectorView.size(),
570 &resultParam, &resultNumParam);
571
572 outResult.clear();
573 if (resultParam != nullptr) {
574 for (unsigned i = 0; i < resultNumParam; ++i)
575 outResult.push_back(resultParam[i]);
576 }
577
578 return errCode;
579}
580
581::FileManagement_ErrCode fileSharePersistPermission(
582 const std::vector<std::shared_ptr<::FileShare_PolicyInfo>> &policies,
583 std::vector<std::shared_ptr<::FileShare_PolicyErrorResult>> &outResult)
584{
585 return callFileSharePermissionActionFunc(
586 Q_OHOS_NAMED_FUNC(::OH_FileShare_PersistPermission),
587 policies, outResult);
588}
589
590::FileManagement_ErrCode fileShareRevokePermission(
591 const std::vector<std::shared_ptr<::FileShare_PolicyInfo>> &policies,
592 std::vector<std::shared_ptr<::FileShare_PolicyErrorResult>> &outResult)
593{
594 return callFileSharePermissionActionFunc(
595 Q_OHOS_NAMED_FUNC(::OH_FileShare_RevokePermission),
596 policies, outResult);
597}
598
599::FileManagement_ErrCode fileShareActivatePermission(
600 const std::vector<std::shared_ptr<::FileShare_PolicyInfo>> &policies,
601 std::vector<std::shared_ptr<::FileShare_PolicyErrorResult>> &outResult)
602{
603 return callFileSharePermissionActionFunc(
604 Q_OHOS_NAMED_FUNC(::OH_FileShare_ActivatePermission),
605 policies, outResult);
606}
607
608::FileManagement_ErrCode fileShareDeactivatePermission(
609 const std::vector<std::shared_ptr<::FileShare_PolicyInfo>> &policies,
610 std::vector<std::shared_ptr<::FileShare_PolicyErrorResult>> &outResult)
611{
612 return callFileSharePermissionActionFunc(
613 Q_OHOS_NAMED_FUNC(::OH_FileShare_DeactivatePermission),
614 policies, outResult);
615}
616
617QOhosOptional<QOhosQpaFunctions::FileShare::PolicyErrorCode> tryMapFileSharePolicyErrorCode(
618 ::FileShare_PolicyErrorCode errorCode)
619{
620 using PolicyErrorCode = QOhosQpaFunctions::FileShare::PolicyErrorCode;
621 switch (errorCode) {
622 case ::FileShare_PolicyErrorCode::PERSISTENCE_FORBIDDEN:
623 return makeQOhosOptional(PolicyErrorCode::PERSISTENCE_FORBIDDEN);
624 case ::FileShare_PolicyErrorCode::INVALID_MODE:
625 return makeQOhosOptional(PolicyErrorCode::INVALID_MODE);
626 case ::FileShare_PolicyErrorCode::INVALID_PATH:
627 return makeQOhosOptional(PolicyErrorCode::INVALID_PATH);
628 case ::FileShare_PolicyErrorCode::PERMISSION_NOT_PERSISTED:
629 return makeQOhosOptional(PolicyErrorCode::PERMISSION_NOT_PERSISTED);
630 }
632}
633
634QList<QOhosQpaFunctions::FileShare::PolicyErrorResult> convertToPolicyErrorResults(
635 const std::vector<std::shared_ptr<::FileShare_PolicyErrorResult>> &policyErrorResults)
636{
637 QList<QOhosQpaFunctions::FileShare::PolicyErrorResult> result;
638 for (const auto &policyErrorResult : policyErrorResults) {
639 result.push_back({
640 .path = policyErrorResult->uri != nullptr
641 ? QString::fromStdString(mapOhosFileUriToPathInJsThread(policyErrorResult->uri))
642 : QString(),
643 .error =
644 tryMapFileSharePolicyErrorCode(policyErrorResult->code),
645 .errorMessage = QLatin1String(
646 policyErrorResult->message != nullptr ? policyErrorResult->message : ""),
647 });
648 }
649
650 return result;
651}
652
653bool isSuccessErrorCode(::FileManagement_ErrCode errorCode)
654{
655 return errorCode == ::FileManagement_ErrCode::ERR_OK;
656}
657
658QOhosOptional<QOhosQpaFunctions::ShareKit::SharedRecord> tryConvertNapiObjectToSharedRecord(QNapi::Object record)
659{
660 auto tryGetOptionalStringProp = [](const QNapi::Object &object, const std::string &propName) {
661 return qTransform(getOptionalProperty<QNapi::String>(object, propName), &QString::fromStdString);
662 };
663
664 auto tryGetOptionalByteArrayProp = [](const QNapi::Object &object, const std::string &propName) {
665 return qTransform(
666 getOptionalProperty<QNapi::TypedArrayOf<std::uint8_t>>(object, propName),
667 [](const auto &napiArray) {
668 return QByteArray(
669 reinterpret_cast<const char *>(napiArray.Data()),
670 napiArray.ByteLength());
671 });
672 };
673
674 auto tryGetOptionalJsonObjectProp = [](const QNapi::Object &object, const std::string &propName) {
675 return qTransform(
676 getOptionalProperty<QNapi::Object>(object, propName),
677 [](const auto &napiObject) {
678 return QOhosJsEnv::fromNapiValue<QJsonObject>(napiObject);
679 });
680 };
681
682 std::string utd = record.get<QNapi::String>("utd");
683 auto optMimeType = utd != QOhosUdsMeta<::OH_UdsHyperlink>::udmfMetaId
684 ? tryMapUtdTypeIdToMimeType(utd)
685 : QOhosOptional<std::string>(QOhosShareKit::mimeTextUriList);
686 if (!optMimeType.has_value()) {
687 qOhosPrintfWarning(
688 "%s: can't map utd '%s' to mimetype, not mapping the record",
689 Q_FUNC_INFO, utd.c_str());
691 }
692
693 auto content = tryGetOptionalStringProp(record, "content");
694 auto uri = tryGetOptionalStringProp(record, "uri");
695 if (!content.has_value() && !uri.has_value()) {
696 qOhosPrintfWarning(
697 "%s: cannot create Shared Record, content and uri properties are empty", Q_FUNC_INFO);
699 }
700
701 return makeQOhosOptional(
702 QOhosQpaFunctions::ShareKit::SharedRecord{
703 .mimeType = QString::fromStdString(optMimeType.value()),
704 .content = content,
705 .filePath = uri,
706 .title = tryGetOptionalStringProp(record, "title"),
707 .label = tryGetOptionalStringProp(record, "label"),
708 .description = tryGetOptionalStringProp(record, "description"),
709 .thumbnail = tryGetOptionalByteArrayProp(record, "thumbnail"),
710 .thumbnailFilePath = tryGetOptionalStringProp(record, "thumbnailUri"),
711 .extraData = qTransform(tryGetOptionalJsonObjectProp(record, "extraData"), std::mem_fn(&QJsonObject::toVariantMap)),
712 });
713}
714
715QOhosShareKit::ShareAbilityType mapShareAbilityTypeFromQpaFunctionsEnum(
717{
718 switch (abilityType) {
729 }
730
731 qOhosReportFatalErrorAndAbort(
732 "%s: unsupported ShareAbilityType value: %d",
733 Q_FUNC_INFO, static_cast<int>(abilityType));
734}
735
736QOhosOptional<std::uint32_t> tryConvertPortNameToSystemPortId(const QString &portName)
737{
738 constexpr const char *serialPortPrefix = "COM";
739 const QString prefix = QLatin1String(serialPortPrefix);
740
741 if (!portName.startsWith(prefix))
742 return {};
743
744 return QtOhos::tryParseStringAsUnsignedInteger<std::uint32_t>(portName.mid(prefix.length()).toStdString());
745}
746
747bool hasSerialPortAccessRightJsImpl(QtOhos::JsState &jsState, std::uint32_t serialPortId)
748{
749 try {
750 return jsState.eval<QNapi::Boolean>("@ohos.usbManager.serial.hasSerialRight(*)", {serialPortId});
751 } catch (const Napi::Error &error) {
752 qOhosPrintfError(
753 "%s: hasSerialRight for port %d failed with error: %s",
754 Q_FUNC_INFO, serialPortId, error.what());
755 return false;
756 }
757}
758
759void requestSerialPortAccessRightJsImpl(
760 QtOhos::JsState &jsState, std::uint32_t serialPortId, QOhosConsumer<bool> resultConsumer)
761{
762 jsState.evalToPromiseOrRejectOnThrow(
763 "@ohos.usbManager.serial.requestSerialRight(*)", {serialPortId})
764 .withContext(std::move(resultConsumer))
765 .onThenWithContext(
766 [](const QtOhos::CallbackInfo &cbInfo, auto &resultConsumer) {
767 bool granted = cbInfo.getFirstArg<QNapi::Boolean>(Q_FUNC_INFO);
768 resultConsumer(granted);
769 })
770 .onCatchWithContext(
771 [](const QtOhos::CallbackInfo &cbInfo, auto &resultConsumer) {
772 QtOhos::logJsCallbackError(
773 cbInfo, "@ohos.usbManager.serial.requestSerialRight() failed");
774 resultConsumer(false);
775 });
776}
777
778void cancelSerialPortAccessRightJsImpl(QtOhos::JsState &jsState, std::uint32_t serialPortId)
779{
780 if (!hasSerialPortAccessRightJsImpl(jsState, serialPortId))
781 return;
782
783 try {
784 jsState.eval("@ohos.usbManager.serial.cancelSerialRight(*)", {serialPortId});
785 } catch (const Napi::Error &error) {
786 qOhosPrintfError(
787 "%s: cancelSerialRight(%u) failed with error (ignoring): %s",
788 Q_FUNC_INFO, serialPortId, error.what());
789 }
790}
791
792class WantInfoImpl : public QOhosQpaFunctions::WantInfo
793{
794public:
795 WantInfoImpl(QNapi::Object want, LaunchReason launchReason);
796
797 QJsonObject jsonObject() const override;
798
799 QOhosOptional<QList<QOhosQpaFunctions::ShareKit::SharedRecord>> tryGetSharedDataRecords() const override;
800
801 QOhosOptional<ContactInfo> tryGetContactInfo() const override;
802
803 LaunchReason launchReason() const override;
804
805private:
806 struct JsScopeData
807 {
808 QNapi::Reference<QNapi::Object> want;
809 };
810
811 std::shared_ptr<JsScopeData> m_jsScopeData;
812 QJsonObject m_jsonObject;
813 LaunchReason m_launchReason;
814};
815
816WantInfoImpl::WantInfoImpl(QNapi::Object want, LaunchReason launchReason)
817 : WantInfo()
818 , m_jsScopeData(
819 QtOhos::makeProxyWithJsThreadDeleter(
820 QtOhos::moveToSharedPtr(
821 JsScopeData {
822 .want = QNapi::Reference<>::makePersistentFrom(want),
823 })))
824 , m_jsonObject(QOhosJsEnv::fromNapiValue<QJsonObject>(want))
825 , m_launchReason(launchReason)
826{
827}
828
829QJsonObject WantInfoImpl::jsonObject() const
830{
831 return m_jsonObject;
832}
833
834QOhosOptional<QList<QOhosQpaFunctions::ShareKit::SharedRecord>> WantInfoImpl::tryGetSharedDataRecords() const
835{
836 using SharedRecord = QOhosQpaFunctions::ShareKit::SharedRecord;
837
838 return QtOhos::evalInJsThreadWithPromise<QOhosOptional<QList<SharedRecord>>>(
839 [&](QtOhos::JsState &jsState, QOhosTaskPromise<QOhosOptional<QList<SharedRecord>>> evalPromise) {
840 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
841 jsState.evalToPromiseOrRejectOnThrow(
842 "@kit.ShareKit.systemShare.getSharedData(*)", {m_jsScopeData->want.Value()})
843 .onThen(
844 [thenPromise = std::move(thenCatchPromises.first)](const QtOhos::CallbackInfo &cbInfo) {
845 QNapi::Object sharedData = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
846
847 auto optRecords = QNapi::getArrayElements<QList<QOhosOptional<SharedRecord>>, QNapi::Object>(
848 sharedData.call<QNapi::Array>("getRecords"), &tryConvertNapiObjectToSharedRecord);
849
850 QList<SharedRecord> records;
851 for (const auto &optRecord : optRecords) {
852 if (optRecord.has_value())
853 records.append(optRecord.value());
854 }
855
856 std::size_t unconvertedRecordsCount = optRecords.size() - records.size();
857 if (unconvertedRecordsCount != 0) {
858 qOhosPrintfWarning(
859 "%s: can't convert %zu Shared Records, ignoring them",
860 Q_FUNC_INFO, unconvertedRecordsCount);
861 }
862
863 thenPromise(makeQOhosOptional(records));
864 })
865 .onCatch(
866 [catchPromise = std::move(thenCatchPromises.second)](const QtOhos::CallbackInfo &cbInfo) {
867 QtOhos::logJsCallbackError(cbInfo, "@kit.ShareKit.systemShare.getSharedData() failed");
868 catchPromise(makeEmptyQOhosOptional());
869 });
870 },
871 Q_FUNC_INFO);
872}
873
874QOhosOptional<QOhosQpaFunctions::WantInfo::ContactInfo> WantInfoImpl::tryGetContactInfo() const
875{
876 using ContactInfo = QOhosQpaFunctions::WantInfo::ContactInfo;
877
878 return QtOhos::evalInJsThreadWithPromise<QOhosOptional<ContactInfo>>(
879 [&](QtOhos::JsState &jsState, QOhosTaskPromise<QOhosOptional<ContactInfo>> evalPromise) {
880 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
881 jsState.evalToPromiseOrRejectOnThrow(
882 "@kit.ShareKit.systemShare.getContactInfo(*)", {m_jsScopeData->want.Value()})
883 .onThen(
884 [thenPromise = std::move(thenCatchPromises.first)](const QtOhos::CallbackInfo &cbInfo) {
885 auto contactInfoObj = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
886 ContactInfo contactInfo = {
887 .contactType = QString::fromStdString(
888 contactInfoObj.get<QNapi::String>("contactType")),
889 .contactId = QString::fromStdString(
890 contactInfoObj.get<QNapi::String>("contactId")),
891 };
892 thenPromise(makeQOhosOptional(contactInfo));
893 })
894 .onCatch(
895 [catchPromise = std::move(thenCatchPromises.second)](const QtOhos::CallbackInfo &cbInfo) {
896 QtOhos::logJsCallbackError(cbInfo, "@kit.ShareKit.systemShare.getContactInfo() failed");
897 catchPromise(makeEmptyQOhosOptional());
898 });
899 },
900 Q_FUNC_INFO);
901}
902
903QOhosQpaFunctions::WantInfo::LaunchReason WantInfoImpl::launchReason() const
904{
905 return m_launchReason;
906}
907
908class QOhosQpaFunctionsImpl : public QOhosQpaFunctions, public std::enable_shared_from_this<QOhosQpaFunctionsImpl>
909{
910public:
911 void setWindowPrivacyMode(QObject *window, bool privacyModeEnabled) override;
912 void setWindowCornerRadius(QObject *window, double radius) override;
913 void tagWindowOrWidgetAsFloatWindow(QObject *windowOrWidget, bool floatWindow) override;
914
915 void setInAppOnlyPasteboardShareOption(bool shareInAppOnly) override;
916 QVariant getImageDataFromPasteboard() const override;
917 QString getTextDataFromPasteboard() const override;
918
919 void setWindowOrWidgetNativeNodeRenderFitPolicyHint(QObject *windowOrWidget, NativeNodeRenderFitPolicy renderFitPolicy) override;
920
921 void setSurfaceBackgroundColor(QObject *windowOrWidget, const QColor &color) override;
922
923 void setMainWindowGeometryPersistencePolicy(WindowGeometryPersistencePolicy policy) override;
924
925 void setWindowKeepScreenOn(QObject *windowOrWidget, bool keepScreenOn) override;
926
927 void setWindowDragResizable(QObject *windowOrWidget, bool dragResizable) override;
928
929 QOhosOptional<double> tryGetNativeWindowId(QObject *window) override;
930 QOhosOptional<double> tryGetScreenDisplayId(QObject *screenObject) override;
931
932 void setOnContinueRequestsHandlerForAbilityInstanceWindow(
933 QObject *windowObject, std::function<void(AbilityOnContinueRequest, QOhosConsumer<AbilityOnContinueResponse>)> requestsHandler) override;
934
935 void setAbilityContinuationActive(
936 QObject *optInstanceMainWindow, bool continuationActive) override;
937
938 Q_NORETURN void restartApp(QOhosOptional<QJsonObject> want) override;
939
940 QJsonObject getAppLaunchWant() override;
941 QSharedPointer<WantInfo> getAppLaunchWantInfo() const override;
942
943 void addNewWantConsumer(QObject *context, QOhosConsumer<QJsonObject> wantConsumer) override;
944 void addNewWantConsumer(
945 QObject *context, QOhosConsumer<QSharedPointer<WantInfo>> wantConsumer) override;
946
947 void startAppProcess(
948 const QString &processId, const QJsonObject &requestWant,
949 const QOhosOptional<StartOptions> &optStartOptions) override;
950
951 bool startAbility(const QJsonObject &want, const QOhosOptional<StartOptions> &options) override;
952
953 bool startAbilityByType(const QString &appType, const QJsonObject &wantParameters) override;
954
955 void startAbilityForResult(
956 const QJsonObject &want, const QOhosOptional<StartOptions> &options,
957 QObject *optInstanceMainWindow, QObject *resultConsumerQtContext,
958 QOhosConsumer<QOhosOptional<AbilityResult>> resultConsumer) override;
959
960 void setDestroyAllowedFlagForAbilityInstances(
961 std::vector<QObject *> instancesMainWindows, bool destroyEnabled) override;
962
963 void setOhosConfigDarkModeFlag(QOhosOptional<bool> darkModeFlag) override;
964
965 QOhosSupplier<QOhosOptional<bool>> makeOhosConfigDarkModeFlagDataSource(
966 QOhosConsumer<QOhosOptional<bool>> darkModeFlagChangedHandler) override;
967
968 QOhosSupplier<double> makeOhosConfigFontSizeScaleDataSource(
969 QOhosConsumer<double> valueChangedHandler) override;
970
971 int getCurrentApplicationVersionCode() override;
972
973 bool readOhosNoUiChildMode() override;
974
975 void startNoUiChildProcess(QString libraryName, QStringList args) override;
976
977 bool hasSerialPortAccessRight(const QString &portName) override;
978
979 void requestSerialPortAccessRight(
980 const QString &portName, QObject *resultConsumerQtContext,
981 QOhosConsumer<std::shared_ptr<void>> resultConsumer) override;
982
983 std::pair<bool, QList<FileShare::PolicyErrorResult>> persistPermission(
984 const QList<FileShare::PolicyInfo> &policyInfos) override;
985
986 std::pair<bool, QList<FileShare::PolicyErrorResult>> revokePermission(
987 const QList<FileShare::PolicyInfo> &policyInfos) override;
988
989 std::pair<bool, QList<FileShare::PolicyErrorResult>> activatePermission(
990 const QList<FileShare::PolicyInfo> &policyInfos) override;
991
992 std::pair<bool, QList<FileShare::PolicyErrorResult>> deactivatePermission(
993 const QList<FileShare::PolicyInfo> &policyInfos) override;
994
995 std::pair<bool, std::vector<bool>> checkPersistent(const QList<FileShare::PolicyInfo> &policyInfos) override;
996
997 bool showFileDialogToAuthorizeFilePath(QObject *parentWindow, const QString &filePath) override;
998
999 void setWindowBrightness(QObject *window, int brightness) override;
1000 void setWindowContrast(QObject *window, int contrast) override;
1001 void setWindowSaturation(QObject *window, int saturation) override;
1002
1003 std::shared_ptr<void> shareDataUsingShareKit(
1004 QObject *optWindowObject, const QList<ShareKit::SharedRecord> &recordsToShare,
1005 const ShareKit::ShareControllerOptions &controllerOptions,
1006 std::function<void()> panelClosedCallback,
1007 QOhosConsumer<ShareKit::ShareOperationResult> optShareCompletedCallback) override;
1008
1009 bool tryOpenLink(QObject *optInstanceMainWindow, const QString &link, QOhosOptional<bool> appLinkingOnly) override;
1010
1011 void setAudioStreamUsageHintProperty(QObject *qObject, AudioStreamUsage usage) override;
1012 QOhosOptional<AudioStreamUsage> tryGetAudioStreamUsageHintProperty(QObject *qObject) override;
1013
1014private:
1015 void processSerialPortPermissionResponse(std::uint32_t serialPortId, bool granted);
1016
1017 std::unordered_map<std::uint32_t, std::vector<QOhosConsumer<std::shared_ptr<void>>>> m_pendingSerialPortsPermissionRequestsConsumers;
1018 std::unordered_map<std::uint32_t, std::weak_ptr<void>> m_grantedSerialPortsPermissionContexts;
1019};
1020
1021void QOhosQpaFunctionsImpl::setWindowPrivacyMode(QObject *window, bool privacyModeEnabled)
1022{
1023 QOhosPlatformWindow::setWindowPrivacyMode(window, privacyModeEnabled);
1024}
1025
1026void QOhosQpaFunctionsImpl::setInAppOnlyPasteboardShareOption(bool shareInAppOnly)
1027{
1029}
1030
1031QVariant QOhosQpaFunctionsImpl::getImageDataFromPasteboard() const
1032{
1033 return QOhosPlatformIntegration::instance()->clipboard()->getPasteboardDataWithLazyFetchOrLocalIfOwner()->imageData();
1034}
1035
1036QString QOhosQpaFunctionsImpl::getTextDataFromPasteboard() const
1037{
1038 return QOhosPlatformIntegration::instance()->clipboard()->getPasteboardDataWithLazyFetchOrLocalIfOwner()->text();
1039}
1040
1041void QOhosQpaFunctionsImpl::setWindowCornerRadius(QObject *windowOrWidget, double radius)
1042{
1043 QOhosPlatformWindow::setWindowCornerRadius(windowOrWidget, radius);
1044}
1045
1046void QOhosQpaFunctionsImpl::tagWindowOrWidgetAsFloatWindow(
1047 QObject *windowOrWidget, bool floatWindow)
1048{
1049 QOhosPlatformWindow::tagWindowOrWidgetAsFloatWindow(windowOrWidget, floatWindow);
1050}
1051
1052void QOhosQpaFunctionsImpl::setWindowOrWidgetNativeNodeRenderFitPolicyHint(
1053 QObject *windowOrWidget, QOhosQpaFunctionsImpl::NativeNodeRenderFitPolicy renderFitPolicyHint)
1054{
1055 QOhosOptional<QOhosPlatformWindow::NativeNodeRenderFitPolicy> policy;
1056 switch (renderFitPolicyHint) {
1059 break;
1062 break;
1063 }
1064
1065 if (policy.has_value()) {
1066 QOhosPlatformWindow::setWindowOrWidgetNativeNodeRenderFitPolicyHint(windowOrWidget, policy.value());
1067 } else {
1068 qOhosReportFatalErrorAndAbort(
1069 "%s: Failed to convert render fit policy hint to QOhosPlatformWindow enum",
1070 Q_FUNC_INFO);
1071 }
1072}
1073
1074void QOhosQpaFunctionsImpl::setSurfaceBackgroundColor(QObject *windowOrWidget, const QColor &color)
1075{
1076 QOhosPlatformWindow::setSurfaceBackgroundColor(windowOrWidget, color);
1077}
1078
1079void QOhosQpaFunctionsImpl::setMainWindowGeometryPersistencePolicy(
1080 WindowGeometryPersistencePolicy geometryPolicyHint)
1081{
1082 QOhosOptional<QOhosPlatformIntegration::WindowGeometryPersistencePolicy> policy;
1083 switch (geometryPolicyHint) {
1086 break;
1089 break;
1092 break;
1093 }
1094
1095 if (policy.has_value()) {
1097 } else {
1098 qOhosReportFatalErrorAndAbort(
1099 "%s: Failed to convert persistence geometry policy hint to QOhosPlatformIntegration enum",
1100 Q_FUNC_INFO);
1101 }
1102}
1103
1104void QOhosQpaFunctionsImpl::setWindowKeepScreenOn(QObject *windowOrWidget, bool keepScreenOn)
1105{
1106 QOhosPlatformWindow::setWindowKeepScreenOn(windowOrWidget, keepScreenOn);
1107}
1108
1109void QOhosQpaFunctionsImpl::setWindowDragResizable(QObject *windowOrWidget, bool dragResizable)
1110{
1111 QOhosPlatformWindow::setWindowDragResizable(windowOrWidget, dragResizable);
1112}
1113
1114QOhosOptional<double> QOhosQpaFunctionsImpl::tryGetNativeWindowId(QObject *window)
1115{
1116 auto *qWindow = qobject_cast<QWindow *>(window);
1117 if (qWindow == nullptr)
1119
1120 auto *platformWindow = QOhosPlatformWindow::fromQWindowOrNull(qWindow);
1121 if (platformWindow == nullptr)
1123
1124 auto internalId = platformWindow->internalWindowId();
1125 auto jsWinId = QWindowProxyRegistry::instance().tryMapInternalWindowIdToJsWindowId(internalId);
1126 if (!jsWinId.has_value())
1128
1129 qOhosPrintfInfo(
1130 "PlatformWindow WIID: %s is returning JsWindowId: %f to the user",
1131 qPrintable(internalId.toString()), jsWinId.value().value());
1132
1133 return makeQOhosOptional(jsWinId.value().value());
1134}
1135
1136QOhosOptional<double> QOhosQpaFunctionsImpl::tryGetScreenDisplayId(QObject *screenObject)
1137{
1138 auto *qScreen = qobject_cast<QScreen *>(screenObject);
1139 if (qScreen == nullptr) {
1140 qOhosPrintfWarning("%s: screenObject argument is not a QScreen", Q_FUNC_INFO);
1142 }
1143 auto *ohosPlatformScreen = static_cast<QOhosPlatformScreen *>(qScreen->handle());
1144
1145 return ohosPlatformScreen != nullptr
1146 ? makeQOhosOptional(ohosPlatformScreen->displayInfo().id.value())
1148}
1149
1150void QOhosQpaFunctionsImpl::setOnContinueRequestsHandlerForAbilityInstanceWindow(
1151 QObject *windowObject, std::function<void(AbilityOnContinueRequest, QOhosConsumer<AbilityOnContinueResponse>)> requestsHandler)
1152{
1153 auto *qWindow = qobject_cast<QWindow *>(windowObject);
1154 if (qWindow == nullptr)
1155 qOhosReportFatalErrorAndAbort("%s: windowObject argument is null or not a QWindow", Q_FUNC_INFO);
1156
1157 auto qWindowRef = QObjectThreadSafeRef(qWindow);
1158 auto sharedRequestsHandler = moveToSharedPtr(std::move(requestsHandler));
1159
1160 struct JsResultContext
1161 {
1162 QNapi::Reference<QNapi::Object> wantParamsReference;
1163 QOhosConsumer<JsState &, QOhosAbilityOnContinueResult> resultConsumer;
1164 };
1165
1167 [&](JsState &jsState) {
1169 jsState.tryGetQAbilityPeerByQWindow(qWindowRef));
1170 if (!uiAbilityPeer) {
1171 qOhosPrintfError(
1172 "%s: no QUiAbilityPeer for window %s, handler not set",
1173 Q_FUNC_INFO, qWindowRef.refName().c_str());
1174 return;
1175 }
1176
1177 uiAbilityPeer->setOnContinueRequestsHandler(
1178 [sharedRequestsHandler](JsState &, QNapi::Object wantParamsObj, auto resultConsumer) {
1179 int sourceVersionCode = wantParamsObj.get<QNapi::Number>("version");
1180 auto jsResultContext = makeProxyWithJsThreadDeleter(std::make_shared<JsResultContext>());
1181 jsResultContext->wantParamsReference = QNapi::Reference<>::makePersistentFrom(wantParamsObj);
1182 jsResultContext->resultConsumer = std::move(resultConsumer);
1183 QtOhos::invokeInQtThread(
1184 [sharedRequestsHandler, sourceVersionCode, jsResultContext]() {
1185 (*sharedRequestsHandler)(
1186 AbilityOnContinueRequest{
1187 .sourceApplicationVersionCode = sourceVersionCode,
1188 },
1189 [jsResultContext](AbilityOnContinueResponse qtResponse) {
1190 QtOhos::invokeInJsThread(
1191 [jsResultContext, qtResponse](JsState &jsState) {
1192 if (qtResponse.status == AbilityOnContinueResponseStatus::Agree) {
1193 auto wantParamsObj = jsResultContext->wantParamsReference.Value();
1194 auto newWantParamsIter = qtResponse.wantObjectParams.constKeyValueBegin();
1195 while (newWantParamsIter != qtResponse.wantObjectParams.constKeyValueEnd()) {
1196 wantParamsObj.set(
1197 newWantParamsIter->first.toStdString(),
1198 newWantParamsIter->second.toStdString());
1199 ++newWantParamsIter;
1200 }
1201 if (qtResponse.exitAppOnSourceDeviceAfterMigration.has_value()) {
1202 wantParamsObj.set(
1203 jsState.eval<QNapi::String>(
1204 "@ohos.app.ability.wantConstant.Params.SUPPORT_CONTINUE_SOURCE_EXIT_KEY"),
1205 qtResponse.exitAppOnSourceDeviceAfterMigration.value());
1206 }
1207 }
1208 auto ohosResult = tryMapAbilityOnContinueResponseStatusToOhos(qtResponse.status);
1209 if (!ohosResult.has_value()) {
1210 qOhosPrintfWarning(
1211 "%s: got illegal status (%d) from request handler, rejecting",
1212 Q_FUNC_INFO, static_cast<int>(qtResponse.status));
1213 }
1214 jsResultContext->resultConsumer(
1215 jsState, ohosResult.value_or(QOhosAbilityOnContinueResult::REJECT));
1216 });
1217 });
1218 });
1219 });
1220 },
1221 Q_FUNC_INFO);
1222}
1223
1224void QOhosQpaFunctionsImpl::setAbilityContinuationActive(
1225 QObject *optInstanceMainWindow, bool continuationActive)
1226{
1227 using ContinueState = enums::ohos::app::ability::AbilityConstant::ContinueState;
1228
1229 auto optInstanceMainWindowRef =
1230 optInstanceMainWindow != nullptr
1231 ? makeQOhosOptional(QtOhos::QObjectThreadSafeRef(optInstanceMainWindow))
1233
1235 [&](JsState &jsState, QOhosTaskPromise<> taskPromise) {
1236 auto optAbilityPeer = tryMapOptMainWindowToAbilityPeer(jsState, optInstanceMainWindowRef);
1237 if (!optAbilityPeer) {
1238 taskPromise();
1239 return;
1240 }
1241
1242 auto continueState = continuationActive ? ContinueState::ACTIVE : ContinueState::INACTIVE;
1243 optAbilityPeer->qAbility().evalToPromiseOrRejectOnThrow(
1244 "context.setMissionContinueState(*)", {jsState.mapOhosEnumToJs(continueState)})
1245 .onCatch(QtOhos::makeErrorLoggingJsCallback("setMissionContinueState()"))
1246 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1247 },
1248 Q_FUNC_INFO);
1249}
1250
1251Q_NORETURN void QOhosQpaFunctionsImpl::restartApp(QOhosOptional<QJsonObject> want)
1252{
1254 [&](JsState &jsState) {
1255 auto napiWant = want.has_value()
1256 ? QNapi::checkedCast<QNapi::Object>(QOhosJsEnv::toNapiValue(jsState.env(), want.value()))
1257 : jsState.appLaunchWant();
1258
1259 constexpr auto sleepTimeBeforeRetry = 3s;
1260
1261 unsigned remainingTries = 3;
1262
1263 while (true) {
1264 --remainingTries;
1265
1266 qOhosPrintfInfo(
1267 "%s: calling restartApp() using Want: %s",
1268 Q_FUNC_INFO, QNapi::toJsonString(napiWant).c_str());
1269
1270 try {
1271 jsState.defaultQAbilityPeer()->qAbility().call(
1272 "context.getApplicationContext().restartApp", {napiWant});
1273
1274 qOhosPrintfWarning("%s: restartApp() call unexpectedly returned, killing self", Q_FUNC_INFO);
1275 killCurrentProcess();
1276 } catch (const Napi::Error &error) {
1277 constexpr std::uint32_t restartTooFrequentlyErrorCode = 16000064;
1278
1279 auto errorCode = QtOhos::tryGetCodeFromJsBusinessError(error);
1280
1281 if (errorCode == restartTooFrequentlyErrorCode && remainingTries != 0) {
1282 qOhosPrintfWarning(
1283 "%s: restartApp() returned with error %u, sleeping before retry",
1284 Q_FUNC_INFO, restartTooFrequentlyErrorCode);
1285
1286 std::this_thread::sleep_for(sleepTimeBeforeRetry);
1287 } else {
1288 auto errorCodeStr = errorCode.has_value()
1289 ? std::to_string(errorCode.value())
1290 : "?";
1291 qOhosPrintfWarning(
1292 "%s: restartApp() returned with error %s, killing self",
1293 Q_FUNC_INFO, errorCodeStr.c_str());
1294
1295 killCurrentProcess();
1296 }
1297 }
1298 }
1299 },
1300 Q_FUNC_INFO);
1301
1302 qOhosReportFatalErrorAndAbort("%s: unexpected return from the JS thread call", Q_FUNC_INFO);
1303}
1304
1305QJsonObject QOhosQpaFunctionsImpl::getAppLaunchWant()
1306{
1307 return getAppLaunchWantInfo()->jsonObject();
1308}
1309
1310QSharedPointer<QOhosQpaFunctions::WantInfo> QOhosQpaFunctionsImpl::getAppLaunchWantInfo() const
1311{
1312 return QtOhos::evalInJsThread(
1313 [](auto &jsState) {
1314 auto optAppLaunchReason = qTransform(
1315 jsState.optAppLaunchParam(),
1316 [&](QNapi::Object appLaunchParam) {
1317 return mapJsLaunchReasonToWantInfoEnumWithFallback(
1318 jsState, appLaunchParam.get<QNapi::Number>("launchReason"));
1319 });
1320 auto appLaunchReason = optAppLaunchReason.value_or(QOhosQpaFunctions::WantInfo::LaunchReason::UNKNOWN);
1321 return QSharedPointer<WantInfoImpl>::create(jsState.appLaunchWant(), appLaunchReason);
1322 },
1323 Q_FUNC_INFO);
1324}
1325
1326void QOhosQpaFunctionsImpl::addNewWantConsumer(QObject *context, QOhosConsumer<QJsonObject> wantConsumer)
1327{
1328 auto sharedWantConsumer = QtOhos::moveToSharedPtr(std::move(wantConsumer));
1329 addNewWantConsumer(
1330 context,
1331 [sharedWantConsumer](QSharedPointer<WantInfo> wantInfo) {
1332 (*sharedWantConsumer)(wantInfo->jsonObject());
1333 });
1334}
1335
1336void QOhosQpaFunctionsImpl::addNewWantConsumer(
1337 QObject *context, QOhosConsumer<QSharedPointer<WantInfo>> wantConsumer)
1338{
1339 auto contextRef = QtOhos::makeQThreadSafeRef(context);
1340 auto sharedWantConsumer = QtOhos::moveToSharedPtr(std::move(wantConsumer));
1342 [&](auto &jsState) {
1343 jsState.addNewWantConsumer(
1344 [contextRef, sharedWantConsumer](QtOhos::JsState &jsState, QNapi::Object napiWant, QNapi::Object launchParam) {
1345 auto launchReason = mapJsLaunchReasonToWantInfoEnumWithFallback(
1346 jsState, launchParam.get<QNapi::Number>("launchReason"));
1347 auto wantInfo = QSharedPointer<WantInfoImpl>::create(napiWant, launchReason);
1348 contextRef.visitInQtThreadIfAlive(
1349 [sharedWantConsumer, wantInfo](auto &) {
1350 (*sharedWantConsumer)(wantInfo);
1351 });
1352 });
1353 },
1354 Q_FUNC_INFO);
1355}
1356
1357void QOhosQpaFunctionsImpl::startAppProcess(
1358 const QString &processId, const QJsonObject &requestWant,
1359 const QOhosOptional<StartOptions> &optStartOptions)
1360{
1362 [&](auto &jsState, QOhosTaskPromise<> taskPromise) {
1363 auto startOptions = optStartOptions.has_value()
1364 ? convertStartOptionsToNapiObject(jsState, optStartOptions.value())
1365 : QNapi::Object();
1366
1367 auto sharedTaskPromise = QtOhos::moveToSharedPtr(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1368 jsState.startAppProcess(
1369 processId.toStdString(),
1370 QNapi::checkedCast<QNapi::Object>(
1371 QOhosJsEnv::toNapiValue(jsState.env(), requestWant)),
1372 startOptions,
1373 [sharedTaskPromise](QtOhos::JsState &) {
1374 (*sharedTaskPromise)();
1375 });
1376 },
1377 Q_FUNC_INFO);
1378}
1379
1380bool QOhosQpaFunctionsImpl::startAbility(const QJsonObject &want, const QOhosOptional<QOhosQpaFunctions::StartOptions> &options)
1381{
1382 return QtOhos::evalInJsThread(
1383 [&](auto &jsState) {
1384 auto mainUiAbility = jsState.defaultQAbilityPeer()->qAbility();
1385 if (mainUiAbility.IsEmpty())
1386 return false;
1387
1388 auto arguments = std::vector<QNapi::ValueWrapper>{QOhosJsEnv::toNapiValue(jsState.env(), want)};
1389 if (options.has_value())
1390 arguments.push_back(convertStartOptionsToNapiObject(jsState, options.value()));
1391
1392 mainUiAbility.call("context.startAbility", arguments);
1393
1394 // FIXME:
1395 // * there should be error code taken from a call to JS `startAbility` function
1396 // * error code should be checked and provided to the returned `operationStatus`
1397 return true;
1398 },
1399 Q_FUNC_INFO);
1400}
1401
1402bool QOhosQpaFunctionsImpl::startAbilityByType(const QString &appType, const QJsonObject &wantParameters)
1403{
1404 // The call result of "context.startAbilityByType" will be synced and returned.
1405 // However, the started ability result won't be synced here.
1406 return QtOhos::evalInJsThreadWithPromise<bool>(
1407 [&](QtOhos::JsState &jsState, QOhosTaskPromise<bool> evalPromise) {
1408 auto qAbility = jsState.defaultQAbilityPeer()->qAbility();
1409 if (qAbility.IsEmpty()) {
1410 evalPromise(false);
1411 return;
1412 }
1413
1414 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
1415 qAbility.evalToPromiseOrRejectOnThrow(
1416 "context.startAbilityByType(*)",
1417 {
1418 appType.toStdString(),
1419 QOhosJsEnv::toNapiValue(jsState.env(), wantParameters),
1420 QNapi::makeObject(
1421 jsState.env(),
1422 {
1423 {
1424 "onResult",
1425 [](const QtOhos::CallbackInfo&) {
1426 qOhosPrintfDebug("startAbilityByType: onResult called");
1427 }
1428 },
1429 {
1430 "onError",
1431 [](const QtOhos::CallbackInfo &cbInfo) {
1432 QtOhos::logJsCallbackError(cbInfo, "startAbilityByType: onError called");
1433 }
1434 }
1435 })
1436 })
1437 .onThen(
1438 [thenPromise = std::move(thenCatchPromises.first)](const QtOhos::CallbackInfo &) {
1439 thenPromise(true);
1440 })
1441 .onCatch(
1442 [catchPromise = std::move(thenCatchPromises.second)](const QtOhos::CallbackInfo &cbInfo) {
1443 QtOhos::logJsCallbackError(cbInfo, "startAbilityByType: failed");
1444 catchPromise(false);
1445 });
1446 },
1447 Q_FUNC_INFO);
1448}
1449
1450void QOhosQpaFunctionsImpl::startAbilityForResult(
1451 const QJsonObject &want, const QOhosOptional<StartOptions> &options,
1452 QObject *optInstanceMainWindow, QObject *resultConsumerQtContext,
1453 QOhosConsumer<QOhosOptional<AbilityResult>> resultConsumer)
1454{
1455 struct Context
1456 {
1457 QtOhos::QObjectThreadSafeRef resultConsumerQtContextRef;
1458 QOhosConsumer<QOhosOptional<AbilityResult>> resultConsumer;
1459 };
1460
1461 auto context = QtOhos::moveToSharedPtr(
1462 Context{
1463 .resultConsumerQtContextRef = QtOhos::QObjectThreadSafeRef(resultConsumerQtContext),
1464 .resultConsumer = std::move(resultConsumer),
1465 });
1466
1467 auto optInstanceMainWindowRef =
1468 optInstanceMainWindow != nullptr
1469 ? makeQOhosOptional(QtOhos::QObjectThreadSafeRef(optInstanceMainWindow))
1471
1473 [context, want, options, optInstanceMainWindowRef](QtOhos::JsState &jsState) {
1474 auto optAbilityPeer = tryMapOptMainWindowToAbilityPeer(jsState, optInstanceMainWindowRef);
1475 if (!optAbilityPeer) {
1476 context->resultConsumerQtContextRef.visitInQtThreadIfAlive(
1477 [context](auto &) {
1478 context->resultConsumer({});
1479 });
1480 return;
1481 }
1482
1483 auto arguments = std::vector<QNapi::ValueWrapper>{QOhosJsEnv::toNapiValue(jsState.env(), want)};
1484 if (options.has_value())
1485 arguments.push_back(convertStartOptionsToNapiObject(jsState, options.value()));
1486
1487 optAbilityPeer->qAbility().evalToPromiseOrRejectOnThrow("context.startAbilityForResult(*)", arguments)
1488 .onThen(
1489 [context](const QtOhos::CallbackInfo &cbInfo) {
1490 QNapi::Object abilityResult = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
1491 int resultCode = abilityResult.get<QNapi::Number>("resultCode");
1492
1493 auto wantOrEmpty = QNapi::getOptionalPropOrEmpty<QNapi::Object>(abilityResult, "want");
1494 auto jsonWant = !wantOrEmpty.IsEmpty()
1495 ? QOhosOptional<QJsonObject>(QOhosJsEnv::fromNapiValue<QJsonObject>(wantOrEmpty))
1496 : makeEmptyQOhosOptional();
1497
1498 context->resultConsumerQtContextRef.visitInQtThreadIfAlive(
1499 [context, resultCode, jsonWant](auto &) {
1500 constexpr int startedAbilityErrorResultCode = -1;
1501 context->resultConsumer(
1502 resultCode != startedAbilityErrorResultCode
1503 ? QOhosOptional<AbilityResult>({resultCode, jsonWant})
1504 : makeEmptyQOhosOptional());
1505 });
1506 })
1507 .onCatch(
1508 [context](const QtOhos::CallbackInfo &cbInfo) {
1509 QtOhos::logJsCallbackError(cbInfo, "Got error from startAbilityForResult()");
1510 context->resultConsumerQtContextRef.visitInQtThreadIfAlive(
1511 [context](auto &) {
1512 context->resultConsumer({});
1513 });
1514 });
1515 });
1516}
1517
1518void QOhosQpaFunctionsImpl::setDestroyAllowedFlagForAbilityInstances(
1519 std::vector<QObject *> instancesMainWindows, bool destroyEnabled)
1520{
1521 std::vector<QtOhos::QObjectThreadSafeRef> instancesMainWindowsRefs;
1522 for (auto *instanceMainWindow : instancesMainWindows)
1523 instancesMainWindowsRefs.emplace_back(instanceMainWindow);
1524
1526 [&](auto &jsState) {
1527 for (const auto &instanceMainWindowRef : instancesMainWindowsRefs) {
1528 auto abilityPeer = jsState.tryGetQAbilityPeerByQWindow(instanceMainWindowRef);
1529 if (abilityPeer)
1530 abilityPeer->destroyAllowedFlag()->store(destroyEnabled);
1531 }
1532 },
1533 Q_FUNC_INFO);
1534}
1535
1536void QOhosQpaFunctionsImpl::setOhosConfigDarkModeFlag(QOhosOptional<bool> darkModeFlag)
1537{
1538 setOhosConfigColorMode(
1539 darkModeFlag.has_value()
1540 ? darkModeFlag.value()
1541 ? OhosConfigurationColorMode::COLOR_MODE_DARK
1542 : OhosConfigurationColorMode::COLOR_MODE_LIGHT
1543 : OhosConfigurationColorMode::COLOR_MODE_NOT_SET);
1544}
1545
1546QOhosSupplier<QOhosOptional<bool>> QOhosQpaFunctionsImpl::makeOhosConfigDarkModeFlagDataSource(
1547 QOhosConsumer<QOhosOptional<bool>> darkModeFlagChangedHandler)
1548{
1549 auto colorModeDataSource = makeOhosConfigColorModeDataSource(
1550 [darkModeFlagChangedHandler = std::move(darkModeFlagChangedHandler)](OhosConfigurationColorMode newColorMode) {
1551 darkModeFlagChangedHandler(
1552 mapOhosConfigurationColorModeToDarkModeFlag(newColorMode));
1553 });
1554 return [colorModeDataSource = std::move(colorModeDataSource)]() {
1555 return mapOhosConfigurationColorModeToDarkModeFlag(colorModeDataSource());
1556 };
1557}
1558
1559QOhosSupplier<double> QOhosQpaFunctionsImpl::makeOhosConfigFontSizeScaleDataSource(
1560 QOhosConsumer<double> valueChangedHandler)
1561{
1563 return makeOhosConfigValueDataSource<double>(
1564 [initFontSizeScale](QtOhos::JsState &) {
1565 return initFontSizeScale;
1566 },
1567 [](QtOhos::JsState &, const QNapi::Object &config) {
1568 return config.get<QNapi::Number>("fontSizeScale").DoubleValue();
1569 },
1570 std::move(valueChangedHandler));
1571}
1572
1573int QOhosQpaFunctionsImpl::getCurrentApplicationVersionCode()
1574{
1575 return QtOhos::evalInJsThread(
1576 [](QtOhos::JsState &jsState) {
1577 auto applicationInfoFlag = jsState.eval<QNapi::Number>(
1578 "@ohos.bundle.bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION");
1579 auto bundleInfo = jsState.eval<QNapi::Object>(
1580 "@ohos.bundle.bundleManager.getBundleInfoForSelfSync(*)", {applicationInfoFlag});
1581 int versionCode = bundleInfo.get<QNapi::Number>("versionCode");
1582
1583 return versionCode;
1584 },
1585 Q_FUNC_INFO);
1586}
1587
1588bool QOhosQpaFunctionsImpl::readOhosNoUiChildMode()
1589{
1590 return QtOhos::evalInJsThread(
1591 [&](auto &jsState) {
1592 return jsState.defaultQAbilityPeer()->instanceId().empty();
1593 },
1594 Q_FUNC_INFO);
1595}
1596
1597void QOhosQpaFunctionsImpl::startNoUiChildProcess(QString libraryName, QStringList args)
1598{
1600 [&](auto &jsState) {
1601 std::vector<std::string> argsVector;
1602 std::transform(
1603 args.begin(), args.end(), std::back_inserter(argsVector),
1604 std::mem_fn(&QString::toStdString));
1605 jsState.startNoUiChildProcess(libraryName.toStdString(), argsVector);
1606 },
1607 Q_FUNC_INFO);
1608}
1609
1610bool QOhosQpaFunctionsImpl::hasSerialPortAccessRight(const QString &portName)
1611{
1612 const auto optSerialPortId = tryConvertPortNameToSystemPortId(portName);
1613 if (!optSerialPortId.has_value()) {
1614 qOhosPrintfError(
1615 "%s: cannot convert serial port name '%s' to port id.",
1616 Q_FUNC_INFO, portName.toStdString().c_str());
1617 return false;
1618 }
1619
1620 return QtOhos::evalInJsThread(
1621 [&](QtOhos::JsState &jsState) {
1622 return hasSerialPortAccessRightJsImpl(jsState, optSerialPortId.value());
1623 },
1624 Q_FUNC_INFO);
1625}
1626
1627void QOhosQpaFunctionsImpl::requestSerialPortAccessRight(
1628 const QString &portName, QObject *resultConsumerQtContext,
1629 QOhosConsumer<std::shared_ptr<void>> resultConsumer)
1630{
1631 auto resultConsumerQtContextRef = QtOhos::makeQThreadSafeRef(resultConsumerQtContext);
1632 auto asyncResultConsumer = [resultConsumerQtContextRef, resultConsumer = std::move(resultConsumer)](std::shared_ptr<void> permissionContext) {
1633 resultConsumerQtContextRef.visitInQtThreadIfAlive(
1634 [resultConsumer = std::move(resultConsumer), permissionContext](auto &resultConsumerQtContext) {
1635 QMetaObject::invokeMethod(
1636 &resultConsumerQtContext,
1637 [resultConsumer = std::move(resultConsumer), permissionContext]() {
1638 resultConsumer(permissionContext);
1639 },
1640 Qt::QueuedConnection);
1641 });
1642 };
1643
1644 const auto optSerialPortId = tryConvertPortNameToSystemPortId(portName);
1645 if (!optSerialPortId.has_value()) {
1646 qOhosPrintfError(
1647 "%s: cannot convert serial port name '%s' to port id.",
1648 Q_FUNC_INFO, portName.toStdString().c_str());
1649
1650 asyncResultConsumer(nullptr);
1651 return;
1652 }
1653
1654 QtOhos::invokeInQtThread(
1655 [serialPortId = optSerialPortId.value(), weakSelf = QtOhos::makeWeakPtr(shared_from_this()), asyncResultConsumer = std::move(asyncResultConsumer)]() {
1656 auto self = weakSelf.lock();
1657 if (!self)
1658 return;
1659
1660 auto alreadyGrantedPermissionContextIt =
1661 self->m_grantedSerialPortsPermissionContexts.find(serialPortId);
1662 auto optAlreadyGrantedPermissionContext =
1663 alreadyGrantedPermissionContextIt != self->m_grantedSerialPortsPermissionContexts.end()
1664 ? alreadyGrantedPermissionContextIt->second.lock()
1665 : nullptr;
1666
1667 if (optAlreadyGrantedPermissionContext) {
1668 asyncResultConsumer(optAlreadyGrantedPermissionContext);
1669 return;
1670 }
1671
1672 self->m_pendingSerialPortsPermissionRequestsConsumers[serialPortId].push_back(
1673 std::move(asyncResultConsumer));
1674
1675 if (self->m_pendingSerialPortsPermissionRequestsConsumers[serialPortId].size() == 1) {
1676 QtOhos::invokeInJsThread(
1677 [serialPortId, weakSelf](QtOhos::JsState &jsState) {
1678 requestSerialPortAccessRightJsImpl(
1679 jsState,
1680 serialPortId,
1681 [serialPortId, weakSelf](bool granted) {
1682 QtOhos::invokeInQtThread(
1683 [serialPortId, weakSelf, granted]() {
1684 auto self = weakSelf.lock();
1685 if (self)
1686 self->processSerialPortPermissionResponse(serialPortId, granted);
1687 });
1688 });
1689 });
1690 }
1691 });
1692}
1693
1694std::pair<bool, QList<QOhosQpaFunctions::FileShare::PolicyErrorResult>> QOhosQpaFunctionsImpl::persistPermission(
1695 const QList<FileShare::PolicyInfo> &policyInfos)
1696{
1697 return QtOhos::evalInJsThread(
1698 [&](QtOhos::JsState &) {
1699 std::vector<std::shared_ptr<::FileShare_PolicyErrorResult>> outResults;
1700 auto retCode = fileSharePersistPermission(
1701 convertToFileSharePolicyInfos(policyInfos), outResults);
1702
1703 return std::make_pair(isSuccessErrorCode(retCode), convertToPolicyErrorResults(outResults));
1704 },
1705 Q_FUNC_INFO);
1706}
1707
1708std::pair<bool, QList<QOhosQpaFunctions::FileShare::PolicyErrorResult>> QOhosQpaFunctionsImpl::revokePermission(
1709 const QList<FileShare::PolicyInfo> &policyInfos)
1710{
1711 return QtOhos::evalInJsThread(
1712 [&](QtOhos::JsState &) {
1713 std::vector<std::shared_ptr<::FileShare_PolicyErrorResult>> outResults;
1714 auto retCode = fileShareRevokePermission(
1715 convertToFileSharePolicyInfos(policyInfos), outResults);
1716
1717 return std::make_pair(isSuccessErrorCode(retCode), convertToPolicyErrorResults(outResults));
1718 },
1719 Q_FUNC_INFO);
1720}
1721
1722std::pair<bool, QList<QOhosQpaFunctions::FileShare::PolicyErrorResult>> QOhosQpaFunctionsImpl::activatePermission(
1723 const QList<FileShare::PolicyInfo> &policyInfos)
1724{
1725 return QtOhos::evalInJsThread(
1726 [&](QtOhos::JsState &) {
1727 std::vector<std::shared_ptr<::FileShare_PolicyErrorResult>> outResults;
1728 auto retCode = fileShareActivatePermission(
1729 convertToFileSharePolicyInfos(policyInfos), outResults);
1730
1731 return std::make_pair(isSuccessErrorCode(retCode), convertToPolicyErrorResults(outResults));
1732 },
1733 Q_FUNC_INFO);
1734}
1735
1736std::pair<bool, QList<QOhosQpaFunctions::FileShare::PolicyErrorResult>> QOhosQpaFunctionsImpl::deactivatePermission(
1737 const QList<FileShare::PolicyInfo> &policyInfos)
1738{
1739 return QtOhos::evalInJsThread(
1740 [&](QtOhos::JsState &) {
1741 std::vector<std::shared_ptr<::FileShare_PolicyErrorResult>> outResults;
1742 auto retCode = fileShareDeactivatePermission(
1743 convertToFileSharePolicyInfos(policyInfos), outResults);
1744
1745 return std::make_pair(isSuccessErrorCode(retCode), convertToPolicyErrorResults(outResults));
1746 },
1747 Q_FUNC_INFO);
1748}
1749
1750std::pair<bool, std::vector<bool>> QOhosQpaFunctionsImpl::checkPersistent(
1751 const QList<FileShare::PolicyInfo> &policyInfos)
1752{
1753 return QtOhos::evalInJsThread(
1754 [&](QtOhos::JsState &) {
1755 std::vector<bool> outResults;
1756 auto retCode = fileShareCheckPersistentPermission(
1757 convertToFileSharePolicyInfos(policyInfos), outResults);
1758
1759 return std::make_pair(isSuccessErrorCode(retCode), outResults);
1760 },
1761 Q_FUNC_INFO);
1762}
1763
1764bool QOhosQpaFunctionsImpl::showFileDialogToAuthorizeFilePath(QObject *parentWindow, const QString &filePath)
1765{
1766 auto *qWindow = qobject_cast<QWindow *>(parentWindow);
1767 if (qWindow == nullptr)
1768 qOhosReportFatalErrorAndAbort("%s: window argument is null or not a QWindow", Q_FUNC_INFO);
1769
1770 auto *platformWindow = QOhosPlatformWindow::fromQWindowOrNull(qWindow);
1771 if (platformWindow == nullptr)
1772 qOhosReportFatalErrorAndAbort("%s: failed to get platform window", Q_FUNC_INFO);
1773
1774 auto eventLoop = std::make_shared<QEventLoop>();
1775 auto filePathAuthorized = std::make_shared<bool>(false);
1776
1778 platformWindow->internalWindowId(), filePath,
1779 [filePathAuthorized, eventLoop](bool result) {
1780 *filePathAuthorized = result;
1781 eventLoop->quit();
1782 });
1783
1784 eventLoop->exec();
1785
1786 return *filePathAuthorized;
1787}
1788
1789void QOhosQpaFunctionsImpl::setWindowBrightness(QObject *window, int brightness)
1790{
1791 auto *qWindow = qobject_cast<QWindow *>(window);
1792 if (qWindow == nullptr)
1793 qOhosReportFatalErrorAndAbort("%s: window argument is null or not a QWindow", Q_FUNC_INFO);
1794
1795 QOhosPlatformWindow::setBrightness(qWindow, brightness);
1796}
1797
1798void QOhosQpaFunctionsImpl::setWindowContrast(QObject *window, int contrast)
1799{
1800 auto *qWindow = qobject_cast<QWindow *>(window);
1801 if (qWindow == nullptr)
1802 qOhosReportFatalErrorAndAbort("%s: window argument is null or not a QWindow", Q_FUNC_INFO);
1803
1804 QOhosPlatformWindow::setContrast(qWindow, contrast);
1805}
1806
1807void QOhosQpaFunctionsImpl::setWindowSaturation(QObject *window, int saturation)
1808{
1809 auto *qWindow = qobject_cast<QWindow *>(window);
1810 if (qWindow == nullptr)
1811 qOhosReportFatalErrorAndAbort("%s: window argument is null or not a QWindow", Q_FUNC_INFO);
1812
1813 QOhosPlatformWindow::setSaturation(qWindow, saturation);
1814}
1815
1816std::shared_ptr<void> QOhosQpaFunctionsImpl::shareDataUsingShareKit(
1817 QObject *optWindowObject, const QList<ShareKit::SharedRecord> &recordsToShare,
1818 const ShareKit::ShareControllerOptions &controllerOptions,
1819 std::function<void()> panelClosedCallback,
1820 QOhosConsumer<ShareKit::ShareOperationResult> optShareCompletedCallback)
1821{
1822 auto *optQWindow = qobject_cast<QWindow *>(optWindowObject);
1823 if (optWindowObject != nullptr && optQWindow == nullptr)
1824 qOhosReportFatalErrorAndAbort("%s: window argument is not a QWindow", Q_FUNC_INFO);
1825
1826 std::vector<QOhosShareKit::SharedRecord> shareKitRecords;
1827 for (const auto &record : recordsToShare) {
1828 shareKitRecords.push_back(
1829 QOhosShareKit::SharedRecord{
1830 .mimeType = record.mimeType.toStdString(),
1831 .content = qTransform(record.content, std::mem_fn(&QString::toStdString)),
1832 .filePath = qTransform(record.filePath, std::mem_fn(&QString::toStdString)),
1833 .title = qTransform(record.title, std::mem_fn(&QString::toStdString)),
1834 .label = qTransform(record.label, std::mem_fn(&QString::toStdString)),
1835 .description = qTransform(record.description, std::mem_fn(&QString::toStdString)),
1836 .thumbnail = record.thumbnail,
1837 .thumbnailFilePath = qTransform(record.thumbnailFilePath, std::mem_fn(&QString::toStdString)),
1838 .extraData = record.extraData,
1839 });
1840 }
1841
1842 auto shareKitControllerOptions = QOhosShareKit::ControllerOptions{
1843 .anchor = qTransform(
1844 controllerOptions.anchorOffset,
1845 [&](auto anchorOffset) {
1847 .windowOffset = anchorOffset,
1848 .size = controllerOptions.anchorSize,
1849 };
1850 }),
1851 .selectionMode = qTransform(
1852 controllerOptions.useSingleSelectionMode,
1853 [](auto singleSelectionMode) {
1854 return singleSelectionMode
1857 }),
1858 .previewMode = qTransform(
1859 controllerOptions.useDefaultPreviewMode,
1860 [](auto defaultPreviewMode) {
1861 return defaultPreviewMode
1864 }),
1865 .excludedAbilities = qTransform(
1866 controllerOptions.excludedAbilities,
1867 [](const auto &excludedAbilities) {
1868 std::vector<QOhosShareKit::ShareAbilityType> outExcludedAbilities;
1869 for (auto excludedAbilityType : excludedAbilities) {
1870 outExcludedAbilities.push_back(
1871 mapShareAbilityTypeFromQpaFunctionsEnum(excludedAbilityType));
1872 }
1873 return outExcludedAbilities;
1874 }),
1875 };
1876
1877 auto shareCompletedCallback = optShareCompletedCallback
1878 ? std::move(optShareCompletedCallback)
1879 : makeQOhosNoOpConsumer();
1880
1881 return QOhosShareKit::shareData(
1882 optQWindow, shareKitRecords, shareKitControllerOptions, std::move(panelClosedCallback),
1883 [shareCompletedCallback = std::move(shareCompletedCallback)](auto shareOperationResult) {
1884 shareCompletedCallback(
1885 ShareKit::ShareOperationResult{
1886 .targetAbilityName = QString::fromStdString(shareOperationResult.targetAbilityName),
1887 });
1888 });
1889}
1890
1891bool QOhosQpaFunctionsImpl::tryOpenLink(QObject *optInstanceMainWindow, const QString &link, QOhosOptional<bool> appLinkingOnly)
1892{
1893 if (optInstanceMainWindow != nullptr && qobject_cast<QWindow *>(optInstanceMainWindow) == nullptr)
1894 qOhosReportFatalErrorAndAbort("%s: the main window argument is not a QWindow", Q_FUNC_INFO);
1895
1896 auto optInstanceMainWindowRef = optInstanceMainWindow != nullptr
1897 ? makeQOhosOptional(QtOhos::QObjectThreadSafeRef(optInstanceMainWindow))
1899
1900 return QtOhos::evalInJsThreadWithPromise<bool>(
1901 [&](QtOhos::JsState &jsState, QOhosTaskPromise<bool> evalPromise) {
1902 auto optAbilityPeer = tryMapOptMainWindowToAbilityPeer(jsState, optInstanceMainWindowRef);
1903 if (!optAbilityPeer) {
1904 evalPromise(false);
1905 return;
1906 }
1907
1908 std::vector<std::pair<std::string, QNapi::ValueWrapper>> openLinkOptions;
1909 if (appLinkingOnly.has_value())
1910 openLinkOptions.emplace_back("appLinkingOnly", appLinkingOnly.value());
1911
1912 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
1913 optAbilityPeer->qAbility().evalToPromiseOrRejectOnThrow(
1914 "context.openLink(*)",
1915 {
1916 link.toStdString(),
1917 QNapi::makeObject(jsState.env(), openLinkOptions),
1918 })
1919 .onThen(
1920 [thenPromise = std::move(thenCatchPromises.first)](const QtOhos::CallbackInfo &) {
1921 thenPromise(true);
1922 })
1923 .onCatch(
1924 [catchPromise = std::move(thenCatchPromises.second)](const QtOhos::CallbackInfo &cbInfo) {
1925 QtOhos::logJsCallbackError(cbInfo, "Got error from openLink()");
1926 catchPromise(false);
1927 });
1928 },
1929 Q_FUNC_INFO);
1930}
1931
1932void QOhosQpaFunctionsImpl::setAudioStreamUsageHintProperty(QObject *qObject, AudioStreamUsage usage)
1933{
1934 setQOhosPropertyOnQObject<QOhosQpaFunctions::AudioStreamUsage, &audioStreamUsageProperty>(qObject, usage);
1935}
1936
1937QOhosOptional<QOhosQpaFunctions::AudioStreamUsage> QOhosQpaFunctionsImpl::tryGetAudioStreamUsageHintProperty(QObject *qObject)
1938{
1939 return tryGetQOhosPropertyFromQObject<QOhosQpaFunctions::AudioStreamUsage, &audioStreamUsageProperty>(qObject);
1940}
1941
1942void QOhosQpaFunctionsImpl::processSerialPortPermissionResponse(std::uint32_t serialPortId, bool granted)
1943{
1944 auto permissionContext = granted
1945 ? QtOhos::makeDestroyNotifier(
1946 [serialPortId, weakSelf = QtOhos::makeWeakPtr(shared_from_this())]() {
1947 QtOhos::invokeInQtThread(
1948 [serialPortId, weakSelf]() {
1949 QtOhos::runInJsThreadAndWait(
1950 [&](QtOhos::JsState &jsState) {
1951 cancelSerialPortAccessRightJsImpl(jsState, serialPortId);
1952 },
1953 Q_FUNC_INFO);
1954
1955 auto self = weakSelf.lock();
1956 if (self)
1957 self->m_grantedSerialPortsPermissionContexts.erase(serialPortId);
1958 });
1959 })
1960 : nullptr;
1961
1962 if (permissionContext)
1963 m_grantedSerialPortsPermissionContexts[serialPortId] = permissionContext;
1964
1965 for (const auto &asyncPermissionRequestConsumer : m_pendingSerialPortsPermissionRequestsConsumers[serialPortId])
1966 asyncPermissionRequestConsumer(permissionContext);
1967
1968 m_pendingSerialPortsPermissionRequestsConsumers.erase(serialPortId);
1969}
1970
1971}
1972
1974
1976
1977QOhosQpaFunctions::WantInfo::WantInfo() = default;
1978
1979QOhosQpaFunctions::WantInfo::~WantInfo() = default;
1980
1982{
1983 static QOhosQpaFunctionsImpl qpaFunctions;
1984 return qpaFunctions;
1985}
1986
1987}
1988
1989QT_END_NAMESPACE
static void setInAppOnlyPasteboardShareOption(bool shareInAppOnly)
static void setMainWindowGeometryPersistencePolicy(WindowGeometryPersistencePolicy policy)
static QOhosPlatformIntegration * instance()
double fontSizeScale() const
static QWindowProxyRegistry & instance()
static std::shared_ptr< QUiAbilityPeer > tryCastFromQAbilityPeerOrNull(std::shared_ptr< QAbilityPeer > qAbilityPeer)
QtOhos::enums::kit::ShareKit::systemShare::SelectionMode SelectionMode
QtOhos::enums::kit::ShareKit::systemShare::ShareAbilityType ShareAbilityType
QtOhos::enums::kit::ShareKit::systemShare::SharePreviewMode SharePreviewMode
void showFileDialogAuthorization(QtOhos::InternalWindowId contextWinId, QString filePath, QOhosConsumer< bool > resultCallback)
void invokeInJsThread(std::function< void(JsState &)> task)
void runInJsThreadAndWait(const std::function< void(JsState &)> &task, std::string callerContextName={})
QOhosQpaFunctions & getQOhosQpaFunctions()
bool isOhosNoUiChildMode()
void invokeInJsThreadAndWaitForContinue(std::function< void(JsState &, QOhosTaskPromise<>)> &&task, std::string callerContextName={})
enums::ohos::app::ability::AbilityConstant::OnContinueResult QOhosAbilityOnContinueResult
std::nullopt_t makeEmptyQOhosOptional()