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
qohosabilitycontext.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 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
5
6#include <QtHarmonyExtras/private/qohosharmonyextrasenums_p.h>
7#include <QtHarmonyExtras/private/qohosoperationstatus_p.h>
8#include <QtHarmonyExtras/private/qohossharekit_p.h>
9#include <QtHarmonyExtras/private/qohosstartoptions_p.h>
10#include <QtHarmonyExtras/private/qohoswantinfo_p.h>
11#include <QtHarmonyExtras/private/qohoswantutils_p.h>
12
13#include <QtGui/qimage.h>
14#include <QtGui/qwindow.h>
15#include <QtGui/private/qohosimageconversions_p.h>
16
17#include <QtCore/qeventloop.h>
18#include <QtCore/qglobalstatic.h>
19#include <QtCore/qhash.h>
20#include <QtCore/qmap.h>
21#include <QtCore/qrandom.h>
22#include <QtCore/qsharedpointer.h>
23#include <QtCore/private/qcore_ohos_p.h>
24#include <QtCore/private/qohoscommon_p.h>
25#include <QtCore/private/qohosjsonconversions_p.h>
26#include <QtCore/private/qohoslogger_p.h>
27
28#include <array>
29#include <cstdint>
30#include <cstring>
31#include <functional>
32#include <map>
33#include <vector>
34
35QT_BEGIN_NAMESPACE
36
37namespace QtHarmonyExtras {
38
39using namespace Private;
40
41namespace {
42
43constexpr const char *qtOnContinueMigrationDataPropertyName = "__io_qt_on_continue_migration_data";
44
45QOhosSupplier<QByteArray> makeUniqueIdsGenerator()
46{
47 return [sequenceNumber = std::uint64_t(0)]() mutable {
48 QByteArray idBytes(32, Qt::Uninitialized);
49 std::memcpy(idBytes.data(), &sequenceNumber, sizeof(sequenceNumber));
50 QRandomGenerator::global()->generate(idBytes.begin() + sizeof(sequenceNumber), idBytes.end());
51 ++sequenceNumber;
52 return idBytes;
53 };
54}
55
56class QOhosOpenLinkOptionsImpl : public OpenLinkOptions
57{
58public:
59 QOhosOpenLinkOptionsImpl();
60
61 void setAppLinkingOnly(bool appLinkingOnly) override;
62
63 std::optional<bool> appLinkingOnly() const;
64
65private:
66 std::optional<bool> m_appLinkingOnly;
67};
68
69QOhosOpenLinkOptionsImpl::QOhosOpenLinkOptionsImpl() = default;
70
71void QOhosOpenLinkOptionsImpl::setAppLinkingOnly(bool appLinkingOnly)
72{
73 m_appLinkingOnly = appLinkingOnly;
74}
75
76std::optional<bool> QOhosOpenLinkOptionsImpl::appLinkingOnly() const
77{
78 return m_appLinkingOnly;
79}
80
81using OnContinueResult = QtOhosHarmonyExtras::enums::ohos::app::ability::AbilityConstant::OnContinueResult;
82
83enum class AbilityOnContinueResponseStatus
84{
85 Agree,
86 Reject,
87 Mismatch,
88};
89
90struct AbilityOnContinueRequest
91{
92 int sourceApplicationVersionCode;
93};
94
95struct AbilityOnContinueResponse
96{
97 AbilityOnContinueResponseStatus status;
98 QMap<QString, QString> wantObjectParams;
99 std::optional<bool> exitAppOnSourceDeviceAfterMigration;
100};
101
102std::optional<OnContinueResult> tryMapAbilityOnContinueResponseStatusToOhos(
103 AbilityOnContinueResponseStatus status)
104{
105 switch (status) {
106 case AbilityOnContinueResponseStatus::Agree:
107 return OnContinueResult::AGREE;
108 case AbilityOnContinueResponseStatus::Reject:
109 return OnContinueResult::REJECT;
110 case AbilityOnContinueResponseStatus::Mismatch:
111 return OnContinueResult::MISMATCH;
112 }
113 return std::nullopt;
114}
115
116void setOnContinueRequestsHandlerForAbilityInstanceWindow(
117 QObject *windowObject,
118 std::function<void(AbilityOnContinueRequest, QOhosConsumer<AbilityOnContinueResponse>)> requestsHandler)
119{
120 auto *qWindow = qobject_cast<QWindow *>(windowObject);
121 if (qWindow == nullptr)
122 qOhosReportFatalErrorAndAbort("%s: windowObject argument is null or not a QWindow", Q_FUNC_INFO);
123
124 auto qWindowRef = QtOhos::QObjectThreadSafeRef(qWindow);
125 auto sharedRequestsHandler = QtOhos::moveToSharedPtr(std::move(requestsHandler));
126
127 struct JsResultContext
128 {
129 QNapi::Reference<QNapi::Object> wantParamsReference;
130 QOhosConsumer<QOhosJsState &, QNapi::Number> resultConsumer;
131 };
132
133 QOhosJsThreadGateway::runAndWait(
134 [&](QOhosJsState &jsState) {
135 auto optQAbility = jsState.tryGetQAbilityByQWindow(qWindowRef);
136 if (!optQAbility) {
137 qOhosPrintfError(
138 "%s: no ability for window %s, handler not set",
139 Q_FUNC_INFO, qWindowRef.refName().c_str());
140 return;
141 }
142
143 jsState.setOnContinueRequestsHandler(
144 optQAbility.value(),
145 [sharedRequestsHandler](QOhosJsState &, QNapi::Object wantParamsObj, auto resultConsumer) {
146 int sourceVersionCode = wantParamsObj.get<QNapi::Number>("version");
147 auto jsResultContext = QtOhos::makeProxyWithJsThreadDeleter(std::make_shared<JsResultContext>());
148 jsResultContext->wantParamsReference = QNapi::Reference<>::makePersistentFrom(wantParamsObj);
149 jsResultContext->resultConsumer = std::move(resultConsumer);
150 QtOhos::invokeInQtThread(
151 [sharedRequestsHandler, sourceVersionCode, jsResultContext]() {
152 (*sharedRequestsHandler)(
153 AbilityOnContinueRequest{
154 .sourceApplicationVersionCode = sourceVersionCode,
155 },
156 [jsResultContext](AbilityOnContinueResponse qtResponse) {
157 QOhosJsThreadGateway::invoke(
158 [jsResultContext, qtResponse](QOhosJsState &jsState) {
159 if (qtResponse.status == AbilityOnContinueResponseStatus::Agree) {
160 auto wantParamsObj = jsResultContext->wantParamsReference.Value();
161 auto newWantParamsIter = qtResponse.wantObjectParams.constKeyValueBegin();
162 while (newWantParamsIter != qtResponse.wantObjectParams.constKeyValueEnd()) {
163 wantParamsObj.set(
164 newWantParamsIter->first.toStdString(),
165 newWantParamsIter->second.toStdString());
166 ++newWantParamsIter;
167 }
168 if (qtResponse.exitAppOnSourceDeviceAfterMigration.has_value()) {
169 wantParamsObj.set(
170 jsState.eval<QNapi::String>(
171 "@ohos.app.ability.wantConstant.Params.SUPPORT_CONTINUE_SOURCE_EXIT_KEY"),
172 qtResponse.exitAppOnSourceDeviceAfterMigration.value());
173 }
174 }
175 auto optResultEnum = tryMapAbilityOnContinueResponseStatusToOhos(qtResponse.status);
176 if (!optResultEnum) {
177 qOhosPrintfWarning(
178 "%s: got illegal status (%d) from requests handler, rejecting the request",
179 Q_FUNC_INFO, static_cast<int>(qtResponse.status));
180 }
181 jsResultContext->resultConsumer(
182 jsState, jsState.mapOhosEnumToJs(optResultEnum.value_or(OnContinueResult::REJECT)));
183 });
184 });
185 });
186 });
187 },
188 Q_FUNC_INFO);
189}
190
191void setDestroyAllowedFlagForAbilityInstances(
192 std::vector<QObject *> instancesMainWindows, bool destroyEnabled)
193{
194 std::vector<QtOhos::QObjectThreadSafeRef> instancesMainWindowsRefs;
195 for (auto *instanceMainWindow : instancesMainWindows)
196 instancesMainWindowsRefs.emplace_back(instanceMainWindow);
197
198 QOhosJsThreadGateway::runAndWait(
199 [&](QOhosJsState &jsState) {
200 for (const auto &instanceMainWindowRef : instancesMainWindowsRefs) {
201 auto optQAbility = jsState.tryGetQAbilityByQWindow(instanceMainWindowRef);
202 if (optQAbility)
203 jsState.setDestroyFromSystemAllowed(optQAbility.value(), destroyEnabled);
204 }
205 },
206 Q_FUNC_INFO);
207}
208
209class QOhosOnContinueContextImpl : public OnContinueContext
210{
211public:
212 QOhosOnContinueContextImpl(int sourceApplicationVersionCode);
213
214 void sendAgreeResponse(const QByteArray &responseData) override;
215 void sendRejectResponse() override;
216 void sendMismatchResponse() override;
217
218 void setExitAppOnSourceDeviceAfterMigration(bool exitAfterMigration) override;
219
220 int sourceApplicationVersionCode() const override;
221
222 AbilityOnContinueResponse response() const;
223
224private:
225 int m_sourceApplicationVersionCode;
226 AbilityOnContinueResponse m_baseResponse;
227 std::optional<bool> m_exitAppOnSourceDeviceAfterMigration;
228};
229
230QOhosOnContinueContextImpl::QOhosOnContinueContextImpl(int sourceApplicationVersionCode)
231 : OnContinueContext()
232 , m_sourceApplicationVersionCode(sourceApplicationVersionCode)
233{
234 sendRejectResponse();
235}
236
237/*!
238 \fn void QtHarmonyExtras::OnContinueContext::sendAgreeResponse(const QByteArray &responseData)
239
240 Sends an agree response to the OnContinue request, carrying \a responseData.
241 Agreeing accepts the continuation process.
242 See \l {https://developer.huawei.com/consumer/en/doc/harmonyos-references-V13/js-apis-app-ability-abilityconstant-V13#oncontinueresult}
243 {OnContinueResult}
244*/
245void QOhosOnContinueContextImpl::sendAgreeResponse(const QByteArray &responseData)
246{
247 m_baseResponse = AbilityOnContinueResponse{
248 .status = AbilityOnContinueResponseStatus::Agree,
249 .wantObjectParams = {
250 {
251 QString::fromUtf8(qtOnContinueMigrationDataPropertyName),
252 QString::fromUtf8(responseData.toBase64())
253 },
254 },
255 .exitAppOnSourceDeviceAfterMigration = {},
256 };
257}
258
259/*!
260 \fn void QtHarmonyExtras::OnContinueContext::sendRejectResponse()
261
262 Sends a reject response to the OnContinue request.
263 Rejecting means the continuation process should not be continued.
264 This is typically used when the target application cannot handle the continuation
265 request for any reason.
266 See \l {https://developer.huawei.com/consumer/en/doc/harmonyos-references-V13/js-apis-app-ability-abilityconstant-V13#oncontinueresult}
267 {OnContinueResult}
268*/
269void QOhosOnContinueContextImpl::sendRejectResponse()
270{
271 m_baseResponse = AbilityOnContinueResponse{
272 .status = AbilityOnContinueResponseStatus::Reject,
273 .wantObjectParams = {},
274 .exitAppOnSourceDeviceAfterMigration = {},
275 };
276}
277
278/*!
279 \fn void OnContinueContext::sendMismatchResponse()
280
281 Sends a mismatch response to the OnContinue request.
282 A mismatch means the continuation process should not be continued - most probably due to
283 source and target application version code difference.
284 See \l {https://developer.huawei.com/consumer/en/doc/harmonyos-references-V13/js-apis-app-ability-abilityconstant-V13#oncontinueresult}
285 {OnContinueResult}
286
287 \sa sourceApplicationVersionCode()
288*/
289void QOhosOnContinueContextImpl::sendMismatchResponse()
290{
291 m_baseResponse = AbilityOnContinueResponse{
292 .status = AbilityOnContinueResponseStatus::Mismatch,
293 .wantObjectParams = {},
294 .exitAppOnSourceDeviceAfterMigration = {},
295 };
296}
297
298/*!
299 \fn void OnContinueContext::setExitAppOnSourceDeviceAfterMigration(bool exitAfterMigration)
300
301 Decides whether the application should automatically exit on the source device after successful
302 migration to the target device.
303
304 The default setting is determined by the platform. As of API17 it's set to "true" by default.
305*/
306void QOhosOnContinueContextImpl::setExitAppOnSourceDeviceAfterMigration(bool exitAfterMigration)
307{
308 m_exitAppOnSourceDeviceAfterMigration = exitAfterMigration;
309}
310
311AbilityOnContinueResponse QOhosOnContinueContextImpl::response() const
312{
313 auto response = m_baseResponse;
314 response.exitAppOnSourceDeviceAfterMigration = m_exitAppOnSourceDeviceAfterMigration;
315 return response;
316}
317
318/*!
319 \fn int QtHarmonyExtras::OnContinueContext::sourceApplicationVersionCode() const
320
321 Returns source application version code. Source application is the one which has started
322 the continuation process. This version code is devlivered as "version" property in
323 onContinue wantParam.
324*/
325int QOhosOnContinueContextImpl::sourceApplicationVersionCode() const
326{
327 return m_sourceApplicationVersionCode;
328}
329
330std::optional<QtOhosHarmonyExtras::enums::ohos::app::ability::AbilityConstant::WindowMode> tryMapWindowModeToOhosOrLogWarning(
331 QOhosStartOptionsData::WindowMode windowMode)
332{
333 namespace AbilityConstant = QtOhosHarmonyExtras::enums::ohos::app::ability::AbilityConstant;
334 using OptionsData = QOhosStartOptionsData;
335
336 switch (windowMode) {
337 case OptionsData::WindowMode::WINDOW_MODE_SPLIT_PRIMARY:
338 return std::make_optional(AbilityConstant::WindowMode::WINDOW_MODE_SPLIT_PRIMARY);
339 case OptionsData::WindowMode::WINDOW_MODE_SPLIT_SECONDARY:
340 return std::make_optional(AbilityConstant::WindowMode::WINDOW_MODE_SPLIT_SECONDARY);
341 case OptionsData::WindowMode::WINDOW_MODE_FULLSCREEN:
342 return std::make_optional(AbilityConstant::WindowMode::WINDOW_MODE_FULLSCREEN);
343 }
344
345 qCWarning(QtForOhos, "%s: got illegal WindowMode: %d", Q_FUNC_INFO, static_cast<int>(windowMode));
346
347 return {};
348}
349
350std::optional<QtOhosHarmonyExtras::enums::ohos::app::ability::contextConstant::ProcessMode> tryMapProcessModeToOhosOrLogWarning(
351 QOhosStartOptionsData::ProcessMode processMode)
352{
353 namespace contextConstant = QtOhosHarmonyExtras::enums::ohos::app::ability::contextConstant;
354 using OptionsData = QOhosStartOptionsData;
355
356 switch (processMode) {
357 case OptionsData::ProcessMode::NEW_PROCESS_ATTACH_TO_PARENT:
358 return std::make_optional(contextConstant::ProcessMode::NEW_PROCESS_ATTACH_TO_PARENT);
359 case OptionsData::ProcessMode::NEW_PROCESS_ATTACH_TO_STATUS_BAR_ITEM:
360 return std::make_optional(contextConstant::ProcessMode::NEW_PROCESS_ATTACH_TO_STATUS_BAR_ITEM);
361 }
362
363 qCWarning(QtForOhos, "%s: got illegal ProcessMode: %d", Q_FUNC_INFO, static_cast<int>(processMode));
364
365 return {};
366}
367
368std::optional<QtOhosHarmonyExtras::enums::ohos::app::ability::contextConstant::StartupVisibility> tryMapStartupVisibilityToOhosOrLogWarning(
369 QOhosStartOptionsData::StartupVisibility startupVisibility)
370{
371 namespace contextConstant = QtOhosHarmonyExtras::enums::ohos::app::ability::contextConstant;
372 using OptionsData = QOhosStartOptionsData;
373
374 switch (startupVisibility) {
375 case OptionsData::StartupVisibility::STARTUP_HIDE:
376 return std::make_optional(contextConstant::StartupVisibility::STARTUP_HIDE);
377 case OptionsData::StartupVisibility::STARTUP_SHOW:
378 return std::make_optional(contextConstant::StartupVisibility::STARTUP_SHOW);
379 }
380
381 qCWarning(QtForOhos, "%s: got illegal StartupVisibility: %d", Q_FUNC_INFO, static_cast<int>(startupVisibility));
382
383 return {};
384}
385
386std::optional<QtOhosHarmonyExtras::enums::ohos::bundle::bundleManager::SupportWindowMode> tryMapSupportWindowModeToOhosOrLogWarning(
387 QOhosStartOptionsData::SupportWindowMode supportWindowMode)
388{
389 namespace bundleManager = QtOhosHarmonyExtras::enums::ohos::bundle::bundleManager;
390 using OptionsData = QOhosStartOptionsData;
391
392 switch (supportWindowMode) {
393 case OptionsData::SupportWindowMode::FULL_SCREEN:
394 return std::make_optional(bundleManager::SupportWindowMode::FULL_SCREEN);
395 case OptionsData::SupportWindowMode::SPLIT:
396 return std::make_optional(bundleManager::SupportWindowMode::SPLIT);
397 case OptionsData::SupportWindowMode::FLOATING:
398 return std::make_optional(bundleManager::SupportWindowMode::FLOATING);
399 }
400
401 qCWarning(QtForOhos, "%s: got illegal SupportWindowMode: %d", Q_FUNC_INFO, static_cast<int>(supportWindowMode));
402
403 return {};
404}
405
406QNapi::Array mapSupportWindowModesToJsEnumsArray(
407 QOhosJsState &jsState, const QList<QOhosStartOptionsData::SupportWindowMode> &supportWindowModes)
408{
409 std::vector<QNapi::ValueWrapper> jsSupportWindowModes;
410 for (auto supportWindowMode : supportWindowModes) {
411 auto optOhosSupportWindowMode = tryMapSupportWindowModeToOhosOrLogWarning(supportWindowMode);
412 if (optOhosSupportWindowMode.has_value())
413 jsSupportWindowModes.push_back(jsState.mapOhosEnumToJs(optOhosSupportWindowMode.value()));
414 }
415
416 return QNapi::makeArray(jsState.env(), jsSupportWindowModes);
417}
418
419QNapi::Object makeJsCompletionHandler(
420 QOhosJsState &jsState, std::shared_ptr<QOhosConsumer<bool, QJsonObject, QString>> qtThreadCompletionHandler)
421{
422 auto makeCompletionCallback = [qtThreadCompletionHandler](bool requestSuccess) {
423 return [qtThreadCompletionHandler, requestSuccess](const QNapi::CallbackInfo &cbInfo) {
424 QNapi::Object elementNameObj;
425 QNapi::String messageValue;
426 cbInfo.getLeadingArgs(Q_FUNC_INFO, elementNameObj, messageValue);
427
428 const QJsonObject elementName = QtOhos::mapNapiObjectToJsonObject(elementNameObj);
429 const QString message = QString::fromStdString(messageValue);
430
431 QtOhos::invokeInQtThread(
432 [qtThreadCompletionHandler, requestSuccess, elementName, message]() {
433 (*qtThreadCompletionHandler)(requestSuccess, elementName, message);
434 });
435 };
436 };
437
438 return QNapi::makeObject(
439 jsState.env(),
440 {
441 {"onRequestSuccess", makeCompletionCallback(true)},
442 {"onRequestFailure", makeCompletionCallback(false)},
443 });
444}
445
446QNapi::Object convertStartOptionsToNapiObject(
447 QOhosJsState &jsState, const QOhosStartOptionsData &opts)
448{
449 auto *env = jsState.env();
450 auto napiOptions = QNapi::Object::New(env);
451
452 auto optOhosWindowMode = opts.windowMode.has_value()
453 ? tryMapWindowModeToOhosOrLogWarning(opts.windowMode.value())
454 : std::nullopt;
455 if (optOhosWindowMode.has_value())
456 napiOptions.set("windowMode", jsState.mapOhosEnumToJs(optOhosWindowMode.value()));
457 if (opts.displayId.has_value())
458 napiOptions.set("displayId", opts.displayId.value());
459 if (opts.withAnimation.has_value())
460 napiOptions.set("withAnimation", opts.withAnimation.value());
461 if (opts.windowLeft.has_value())
462 napiOptions.set("windowLeft", opts.windowLeft.value());
463 if (opts.windowTop.has_value())
464 napiOptions.set("windowTop", opts.windowTop.value());
465 if (opts.windowWidth.has_value())
466 napiOptions.set("windowWidth", opts.windowWidth.value());
467 if (opts.windowHeight.has_value())
468 napiOptions.set("windowHeight", opts.windowHeight.value());
469 auto optOhosProcessMode = opts.processMode.has_value()
470 ? tryMapProcessModeToOhosOrLogWarning(opts.processMode.value())
471 : std::nullopt;
472 if (optOhosProcessMode.has_value())
473 napiOptions.set("processMode", jsState.mapOhosEnumToJs(optOhosProcessMode.value()));
474 auto optOhosStartupVisibility = opts.startupVisibility.has_value()
475 ? tryMapStartupVisibilityToOhosOrLogWarning(opts.startupVisibility.value())
476 : std::nullopt;
477 if (optOhosStartupVisibility.has_value())
478 napiOptions.set("startupVisibility", jsState.mapOhosEnumToJs(optOhosStartupVisibility.value()));
479 if (opts.windowIcon.has_value()) {
480 auto windowIcon = opts.windowIcon.value().value<QImage>();
481 if (!windowIcon.isNull())
482 napiOptions.set("startWindowIcon", makeOhosNapiPixelMapFromQImage(jsState, windowIcon));
483 }
484 if (opts.windowBackgroundColorHex.has_value())
485 napiOptions.set("startWindowBackgroundColor", opts.windowBackgroundColorHex.value().toStdString());
486 if (opts.supportWindowModes.has_value()) {
487 auto jsSupportWindowModes = mapSupportWindowModesToJsEnumsArray(jsState, opts.supportWindowModes.value());
488 if (jsSupportWindowModes.Length() != 0)
489 napiOptions.set("supportWindowModes", jsSupportWindowModes);
490 else
491 qCWarning(QtForOhos, "%s: OHOS doesn't support empty supportWindowModes, skipping", Q_FUNC_INFO);
492 }
493 if (opts.minWindowWidth.has_value())
494 napiOptions.set("minWindowWidth", opts.minWindowWidth.value());
495 if (opts.minWindowHeight.has_value())
496 napiOptions.set("minWindowHeight", opts.minWindowHeight.value());
497 if (opts.maxWindowWidth.has_value())
498 napiOptions.set("maxWindowWidth", opts.maxWindowWidth.value());
499 if (opts.maxWindowHeight.has_value())
500 napiOptions.set("maxWindowHeight", opts.maxWindowHeight.value());
501 if (opts.optCompletionHandler)
502 napiOptions.set("completionHandler", makeJsCompletionHandler(jsState, opts.optCompletionHandler));
503 if (opts.hideStartWindow.has_value())
504 napiOptions.set("hideStartWindow", opts.hideStartWindow.value());
505 if (opts.windowCreateParams.has_value()) {
506 const auto &windowCreateParams = opts.windowCreateParams.value();
507 std::vector<std::pair<std::string, QNapi::ValueWrapper>> windowCreateParamsProps;
508 if (windowCreateParams.setWindowFadeInOutAnimation) {
509 windowCreateParamsProps.emplace_back(
510 "animationParams",
511 QNapi::makeObject(
512 env,
513 {
514 {
515 "type",
516 jsState.mapOhosEnumToJs(
517 QtOhosHarmonyExtras::enums::ohos::window::AnimationType::FADE_IN_OUT),
518 }
519 }));
520 }
521 napiOptions.set("windowCreateParams", QNapi::makeObject(env, windowCreateParamsProps));
522 }
523
524 return napiOptions;
525}
526
527void requestStartAbilityForResult(
528 const Want &want, std::optional<QOhosStartOptionsData> options,
529 QWindow *optInstanceMainWindow, QObject *callerContext,
530 std::function<void(std::optional<StartAbilityResult>)> resultCallback)
531{
532 struct Context
533 {
534 std::function<void(std::optional<StartAbilityResult>)> resultCallback;
535 QtOhos::QObjectThreadSafeRef resultConsumerQtContextRef;
536 };
537
538 auto context = QtOhos::moveToSharedPtr(
539 Context{
540 .resultCallback = std::move(resultCallback),
541 .resultConsumerQtContextRef = QtOhos::QObjectThreadSafeRef(callerContext),
542 });
543
544 auto resultConsumer = [context](std::optional<QOhosAbilityResult> optAbilityResult) {
545 if (optAbilityResult.has_value()) {
546 auto abilityResult = optAbilityResult.value();
547 auto want = abilityResult.want.has_value()
548 ? std::optional(convertWantFromJsonObject(abilityResult.want.value()))
549 : std::nullopt;
550 context->resultCallback(StartAbilityResult{abilityResult.resultCode, want});
551 } else {
552 context->resultCallback(std::nullopt);
553 }
554 };
555
556 auto wantJson = convertWantToJsonObject(want);
557 auto optInstanceMainWindowRef =
558 optInstanceMainWindow != nullptr
559 ? std::make_optional(QtOhos::QObjectThreadSafeRef(optInstanceMainWindow))
560 : std::nullopt;
561
562 QOhosJsThreadGateway::invoke(
563 [context, resultConsumer, wantJson, options, optInstanceMainWindowRef](QOhosJsState &jsState) {
564 auto optUiAbility = optInstanceMainWindowRef.has_value()
565 ? jsState.tryGetQAbilityByQWindow(optInstanceMainWindowRef.value())
566 : jsState.defaultQAbility();
567 if (!optUiAbility.has_value()) {
568 context->resultConsumerQtContextRef.visitInQtThreadIfAlive(
569 [resultConsumer](auto &) {
570 resultConsumer({});
571 });
572 return;
573 }
574
575 auto arguments = std::vector<QNapi::ValueWrapper>{QtOhos::mapJsonObjectToNapiObject(jsState.env(), wantJson)};
576 if (options.has_value())
577 arguments.push_back(convertStartOptionsToNapiObject(jsState, options.value()));
578
579 optUiAbility.value().evalToPromiseOrRejectOnThrow("context.startAbilityForResult(*)", arguments)
580 .onThen(
581 [context, resultConsumer](const QOhosCallbackInfo &cbInfo) {
582 QNapi::Object abilityResult = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
583 int resultCode = abilityResult.get<QNapi::Number>("resultCode");
584
585 auto wantOrEmpty = QNapi::getOptionalPropOrEmpty<QNapi::Object>(abilityResult, "want");
586 auto jsonWant = !wantOrEmpty.IsEmpty()
587 ? std::optional<QJsonObject>(QtOhos::mapNapiObjectToJsonObject(wantOrEmpty))
588 : std::nullopt;
589
590 context->resultConsumerQtContextRef.visitInQtThreadIfAlive(
591 [resultConsumer, resultCode, jsonWant](auto &) {
592 constexpr int startedAbilityErrorResultCode = -1;
593 resultConsumer(
594 resultCode != startedAbilityErrorResultCode
595 ? std::optional<QOhosAbilityResult>({resultCode, jsonWant})
596 : std::nullopt);
597 });
598 })
599 .onCatch(
600 [context, resultConsumer](const QOhosCallbackInfo &cbInfo) {
601 QtOhos::logJsCallbackError(cbInfo, "Got error from startAbilityForResult()");
602 context->resultConsumerQtContextRef.visitInQtThreadIfAlive(
603 [resultConsumer](auto &) {
604 resultConsumer({});
605 });
606 });
607 });
608}
609
610class QOhosBaseAbilityContextImpl : public AbilityContext
611{
612protected:
613 QOhosBaseAbilityContextImpl();
614
615 QByteArray generateUniqueId();
616
617 void startAbilityForResultImpl(
618 const Want &want, QWindow *optInstanceMainWindow,
619 std::optional<QOhosStartOptionsData> qpaStartOptions,
620 QObject *context, std::function<void(std::optional<StartAbilityResult>)> callback);
621
622 void shareDataWithShareKitImpl(
623 QWindow *optMainWindow, const QList<std::shared_ptr<ShareKit::SharedRecord>> &records,
624 std::shared_ptr<ShareKit::ShareControllerOptions> controllerOptions,
625 QObject *context,
626 std::function<void(std::shared_ptr<ShareKit::ShareOperationResult>)> onShareCompleted,
627 std::function<void()> onPanelClosed);
628
629private:
630 QOhosSupplier<QByteArray> m_uniqueIdsGenerator;
631 QHash<QByteArray, std::shared_ptr<void>> m_shareDataRequestsHandles;
632};
633
634class QOhosDefaultAbilityContextImpl : public QOhosBaseAbilityContextImpl
635{
636public:
637 QOhosDefaultAbilityContextImpl();
638
639 void setDestroyFromSystemEnabled(bool destroyEnabled) override;
640
641 void startAbilityForResult(
642 const Want &want, std::shared_ptr<StartOptions> options, QObject *context,
643 std::function<void(std::optional<StartAbilityResult>)> callback) override;
644
645 void shareDataWithShareKit(
646 const QList<std::shared_ptr<ShareKit::SharedRecord>> &records,
647 std::shared_ptr<ShareKit::ShareControllerOptions> controllerOptions,
648 QObject *context,
649 std::function<void(std::shared_ptr<ShareKit::ShareOperationResult>)> onShareCompleted,
650 std::function<void()> onPanelClosed) override;
651
652 bool tryOpenLink(const QString &link, std::shared_ptr<OpenLinkOptions> options) override;
653
654 void setContinuationActive(bool continuationActive) override;
655};
656
657Q_GLOBAL_STATIC(QOhosDefaultAbilityContextImpl, s_defaultAbilityContextInstance)
658
659class QOhosAbilityContextImpl : public QOhosBaseAbilityContextImpl
660{
661public:
662 QOhosAbilityContextImpl(QWindow *instanceMainWindow);
663
664 void setDestroyFromSystemEnabled(bool destroyEnabled) override;
665
666 void startAbilityForResult(
667 const Want &want, std::shared_ptr<StartOptions> options, QObject *context,
668 std::function<void(std::optional<StartAbilityResult>)> callback) override;
669
670 void shareDataWithShareKit(
671 const QList<std::shared_ptr<ShareKit::SharedRecord>> &records,
672 std::shared_ptr<ShareKit::ShareControllerOptions> controllerOptions,
673 QObject *context,
674 std::function<void(std::shared_ptr<ShareKit::ShareOperationResult>)> onShareCompleted,
675 std::function<void()> onPanelClosed) override;
676
677 bool tryOpenLink(const QString &link, std::shared_ptr<OpenLinkOptions> options) override;
678
679 void setContinuationActive(bool continuationActive) override;
680
681private:
682 QPointer<QWindow> m_instanceMainWindow;
683};
684
685std::map<QWindow *, std::unique_ptr<QOhosAbilityContextImpl>> abilityContextsMap;
686
687QOhosBaseAbilityContextImpl::QOhosBaseAbilityContextImpl()
688 : m_uniqueIdsGenerator(makeUniqueIdsGenerator())
689{
690}
691
692QByteArray QOhosBaseAbilityContextImpl::generateUniqueId()
693{
694 return m_uniqueIdsGenerator();
695}
696
697void QOhosBaseAbilityContextImpl::startAbilityForResultImpl(
698 const Want &want, QWindow *optInstanceMainWindow,
699 std::optional<QOhosStartOptionsData> qpaStartOptions,
700 QObject *context, std::function<void(std::optional<StartAbilityResult>)> callback)
701{
702 requestStartAbilityForResult(
703 want, std::move(qpaStartOptions), optInstanceMainWindow, context,
704 std::move(callback));
705}
706
707void QOhosBaseAbilityContextImpl::shareDataWithShareKitImpl(
708 QWindow *optMainWindow, const QList<std::shared_ptr<ShareKit::SharedRecord>> &records,
709 std::shared_ptr<ShareKit::ShareControllerOptions> controllerOptions,
710 QObject *context,
711 std::function<void(std::shared_ptr<ShareKit::ShareOperationResult>)> onShareCompleted,
712 std::function<void()> onPanelClosed)
713{
714 auto selfPtr = QPointer<QOhosBaseAbilityContextImpl>(this);
715 auto contextPtr = QPointer<QObject>(context);
716 auto requestId = generateUniqueId();
717 auto requestHandle = shareData(
718 optMainWindow, records, controllerOptions,
719 [selfPtr, contextPtr, requestId, onPanelClosed]() {
720 if (!selfPtr.isNull())
721 selfPtr->m_shareDataRequestsHandles.remove(requestId);
722 if (!contextPtr.isNull() && onPanelClosed)
723 onPanelClosed();
724 },
725 [contextPtr, onShareCompleted](auto shareOperationResult) {
726 if (!contextPtr.isNull() && onShareCompleted)
727 onShareCompleted(shareOperationResult);
728 }
729 );
730 m_shareDataRequestsHandles.insert(requestId, requestHandle);
731}
732
733QOhosDefaultAbilityContextImpl::QOhosDefaultAbilityContextImpl() = default;
734
735void QOhosDefaultAbilityContextImpl::setDestroyFromSystemEnabled(bool destroyEnabled)
736{
737 qCDebug(QtForOhos, "%s: setting destroyEnabled=%d for all instances", Q_FUNC_INFO, destroyEnabled);
738
739 std::vector<QObject *> instancesMainWindows;
740 for (const auto &contextEntry : abilityContextsMap)
741 instancesMainWindows.push_back(contextEntry.first);
742
743 setDestroyAllowedFlagForAbilityInstances(instancesMainWindows, destroyEnabled);
744}
745
746void QOhosDefaultAbilityContextImpl::startAbilityForResult(
747 const Want &want, std::shared_ptr<StartOptions> options, QObject *context,
748 std::function<void(std::optional<StartAbilityResult>)> callback)
749{
750 startAbilityForResultImpl(
751 want, nullptr,
752 options ? tryConvertStartOptionsToQpaFunctionsStruct(*options) : std::nullopt,
753 context, std::move(callback));
754}
755
756void QOhosDefaultAbilityContextImpl::shareDataWithShareKit(
757 const QList<std::shared_ptr<ShareKit::SharedRecord>> &records,
758 std::shared_ptr<ShareKit::ShareControllerOptions> controllerOptions,
759 QObject *context,
760 std::function<void(std::shared_ptr<ShareKit::ShareOperationResult>)> onShareCompleted,
761 std::function<void()> onPanelClosed)
762{
763 shareDataWithShareKitImpl(
764 nullptr, records, controllerOptions, context,
765 std::move(onShareCompleted), std::move(onPanelClosed));
766}
767
768bool startAbilityByTypeImpl(const QString &appType, const QJsonObject &wantParameters)
769{
770 // The call result of "context.startAbilityByType" will be synced and returned.
771 // However, the started ability result won't be synced here.
772 return QOhosJsThreadGateway::evalWithPromise<bool>(
773 [&](QOhosJsState &jsState, QOhosTaskPromise<bool> evalPromise) {
774 auto optQAbility = jsState.defaultQAbility();
775 if (!optQAbility.has_value()) {
776 evalPromise(false);
777 return;
778 }
779
780 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
781 optQAbility.value().evalToPromiseOrRejectOnThrow(
782 "context.startAbilityByType(*)",
783 {
784 appType.toStdString(),
785 QtOhos::mapJsonObjectToNapiObject(jsState.env(), wantParameters),
786 QNapi::makeObject(
787 jsState.env(),
788 {
789 {
790 "onResult",
791 [](const QOhosCallbackInfo&) {
792 qOhosPrintfDebug("startAbilityByType: onResult called");
793 }
794 },
795 {
796 "onError",
797 [](const QOhosCallbackInfo &cbInfo) {
798 QtOhos::logJsCallbackError(cbInfo, "startAbilityByType: onError called");
799 }
800 }
801 })
802 })
803 .onThen(
804 [thenPromise = std::move(thenCatchPromises.first)](const QOhosCallbackInfo &) {
805 thenPromise(true);
806 })
807 .onCatch(
808 [catchPromise = std::move(thenCatchPromises.second)](const QOhosCallbackInfo &cbInfo) {
809 QtOhos::logJsCallbackError(cbInfo, "startAbilityByType: failed");
810 catchPromise(false);
811 });
812 },
813 Q_FUNC_INFO);
814}
815
816bool tryOpenLinkImpl(QObject *optInstanceMainWindow, const QString &link, std::optional<bool> appLinkingOnly)
817{
818 if (optInstanceMainWindow != nullptr && qobject_cast<QWindow *>(optInstanceMainWindow) == nullptr)
819 qOhosReportFatalErrorAndAbort("%s: the main window argument is not a QWindow", Q_FUNC_INFO);
820
821 auto optInstanceMainWindowRef = optInstanceMainWindow != nullptr
822 ? std::make_optional(QtOhos::QObjectThreadSafeRef(optInstanceMainWindow))
823 : std::nullopt;
824
825 return QOhosJsThreadGateway::evalWithPromise<bool>(
826 [&](QOhosJsState &jsState, QOhosTaskPromise<bool> evalPromise) {
827 auto optUiAbility = optInstanceMainWindowRef.has_value()
828 ? jsState.tryGetQAbilityByQWindow(optInstanceMainWindowRef.value())
829 : jsState.defaultQAbility();
830 if (!optUiAbility.has_value()) {
831 evalPromise(false);
832 return;
833 }
834
835 std::vector<std::pair<std::string, QNapi::ValueWrapper>> openLinkOptions;
836 if (appLinkingOnly.has_value())
837 openLinkOptions.emplace_back("appLinkingOnly", appLinkingOnly.value());
838
839 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
840 optUiAbility.value().evalToPromiseOrRejectOnThrow(
841 "context.openLink(*)",
842 {
843 link.toStdString(),
844 QNapi::makeObject(jsState.env(), openLinkOptions),
845 })
846 .onThen(
847 [thenPromise = std::move(thenCatchPromises.first)](const QOhosCallbackInfo &) {
848 thenPromise(true);
849 })
850 .onCatch(
851 [catchPromise = std::move(thenCatchPromises.second)](const QOhosCallbackInfo &cbInfo) {
852 QtOhos::logJsCallbackError(cbInfo, "Got error from openLink()");
853 catchPromise(false);
854 });
855 },
856 Q_FUNC_INFO);
857}
858
859void setContinuationActiveImpl(QObject *optInstanceMainWindow, bool continuationActive)
860{
861 using ContinueState = QtOhosHarmonyExtras::enums::ohos::app::ability::AbilityConstant::ContinueState;
862
863 auto optInstanceMainWindowRef = optInstanceMainWindow != nullptr
864 ? std::make_optional(QtOhos::QObjectThreadSafeRef(optInstanceMainWindow))
865 : std::nullopt;
866
867 QOhosJsThreadGateway::invokeAndWaitForContinue(
868 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
869 auto optUiAbility = optInstanceMainWindowRef.has_value()
870 ? jsState.tryGetQAbilityByQWindow(optInstanceMainWindowRef.value())
871 : jsState.defaultQAbility();
872 if (!optUiAbility.has_value()) {
873 taskPromise();
874 return;
875 }
876
877 auto continueState = continuationActive ? ContinueState::ACTIVE : ContinueState::INACTIVE;
878 optUiAbility.value().evalToPromiseOrRejectOnThrow(
879 "context.setMissionContinueState(*)", {jsState.mapOhosEnumToJs(continueState)})
880 .onCatch(QtOhos::makeErrorLoggingJsCallback("setMissionContinueState()"))
881 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
882 },
883 Q_FUNC_INFO);
884}
885
886bool QOhosDefaultAbilityContextImpl::tryOpenLink(const QString &link, std::shared_ptr<OpenLinkOptions> options)
887{
888 return tryOpenLinkImpl(
889 nullptr, link,
890 options
891 ? static_cast<const QOhosOpenLinkOptionsImpl &>(*options).appLinkingOnly()
892 : std::nullopt);
893}
894
895void QOhosDefaultAbilityContextImpl::setContinuationActive(bool continuationActive)
896{
897 setContinuationActiveImpl(nullptr, continuationActive);
898}
899
900QOhosAbilityContextImpl::QOhosAbilityContextImpl(QWindow *instanceMainWindow)
901 : m_instanceMainWindow(instanceMainWindow)
902{
903 setOnContinueRequestsHandlerForAbilityInstanceWindow(
904 instanceMainWindow,
905 [self = QPointer<QOhosAbilityContextImpl>(this)](auto request, auto responseConsumer) {
906 auto context = std::make_shared<QOhosOnContinueContextImpl>(request.sourceApplicationVersionCode);
907
908 if (!self.isNull())
909 Q_EMIT self->continueRequestReceived(context);
910 else
911 context->sendRejectResponse();
912
913 QtOhos::invokeInQtThread(
914 [response = context->response(), responseConsumer = std::move(responseConsumer)]() {
915 responseConsumer(response);
916 });
917 });
918}
919
920/*!
921 \fn void QtHarmonyExtras::AbilityContext::setDestroyFromSystemEnabled(bool destroyEnabled)
922
923 Sets whether the Ability can be automatically destroyed by the system when the user clicks on
924 the window's "close" button. If \a destroyEnabled is \c true, the system destroys the Ability
925 automatically (and Qt needs to adapt to this). If \a destroyEnabled = \c false, the window is
926 not automatically destroyed, but instead standard Qt path for window close is triggered, i.e.
927 QWindow::close().
928
929 By default, the flag is set to \c false.
930
931 When called on the default AbilityContext instance it sets the flag to \a destroyEnabled
932 for all Ability instances.
933*/
934void QOhosAbilityContextImpl::setDestroyFromSystemEnabled(bool destroyEnabled)
935{
936 if (m_instanceMainWindow.isNull()) {
937 qCWarning(QtForOhos, "%s: called on destroyed instance, ignoring", Q_FUNC_INFO);
938 return;
939 }
940
941 qCDebug(
942 QtForOhos, "%s: setting destroyEnabled=%d for window %p",
943 Q_FUNC_INFO, destroyEnabled, m_instanceMainWindow.data());
944
945 setDestroyAllowedFlagForAbilityInstances(
946 {m_instanceMainWindow.data()}, destroyEnabled);
947}
948
949/*!
950 \fn void QtHarmonyExtras::AbilityContext::startAbilityForResult(const QtHarmonyExtras::Want &want, std::shared_ptr<QtHarmonyExtras::StartOptions> options, QObject *context, std::function<void(std::optional<QtHarmonyExtras::StartAbilityResult>)> callback)
951
952 Starts a UIAbility with a given \a want and \a options and delivers the result by invoking \a callback on the thread of \a context;
953 if \a context is destroyed before the result arrives, \a callback is not invoked. To start the UIAbility, at least bundleName and abilityName properties must be set.
954 Pass a null \a options to start without any start options.
955 On success \a callback receives the ability result; on failure (for example, the UIAbility was killed) it receives an empty std::optional.
956 See \l {https://developer.huawei.com/consumer/en/doc/harmonyos-references/js-apis-inner-application-uiabilitycontext#startabilityforresult-2}
957 {UIAbilityContext.startAbilityForResult}
958*/
959void QOhosAbilityContextImpl::startAbilityForResult(
960 const Want &want, std::shared_ptr<StartOptions> options, QObject *context,
961 std::function<void(std::optional<StartAbilityResult>)> callback)
962{
963 startAbilityForResultImpl(
964 want, m_instanceMainWindow,
965 options ? tryConvertStartOptionsToQpaFunctionsStruct(*options) : std::nullopt,
966 context, std::move(callback));
967}
968
969/*!
970 \fn virtual void QtHarmonyExtras::AbilityContext::shareDataWithShareKit(const QList<std::shared_ptr<ShareKit::SharedRecord>> &records, std::shared_ptr<ShareKit::ShareControllerOptions> controllerOptions, QObject *context, std::function<void(std::shared_ptr<ShareKit::ShareOperationResult>)> onShareCompleted, std::function<void()> onPanelClosed) = 0
971
972 Share provided \a records with other applications using an inter-application mechanism called ShareKit. Share Kit panel can be controlled
973 with a given \a controllerOptions. When called on the default AbilityContext instance, it shares \a records using the default UiAbility.
974
975 Results are delivered by invoking the callbacks on the thread of \a context; if \a context is destroyed the callbacks are not invoked.
976 \a onShareCompleted is called when the User selects an application for sharing (can be called multiple times).
977 \a onPanelClosed, if set, is called when the sharing panel is closed.
978
979 See \l {https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V5/share-introduction-V5}{Share Kit}
980*/
981void QOhosAbilityContextImpl::shareDataWithShareKit(
982 const QList<std::shared_ptr<ShareKit::SharedRecord>> &records,
983 std::shared_ptr<ShareKit::ShareControllerOptions> controllerOptions,
984 QObject *context,
985 std::function<void(std::shared_ptr<ShareKit::ShareOperationResult>)> onShareCompleted,
986 std::function<void()> onPanelClosed)
987{
988 shareDataWithShareKitImpl(
989 m_instanceMainWindow, records, controllerOptions, context,
990 std::move(onShareCompleted), std::move(onPanelClosed));
991}
992
993/*!
994 \fn virtual bool QtHarmonyExtras::AbilityContext::tryOpenLink(const QString &link, std::shared_ptr<OpenLinkOptions> options) = 0
995
996 Use provided \a link and \a options to open application with a deep link; pass a null \a options
997 to open without any options.
998 Returns true if successful, false otherwise.
999
1000 See \l {https://developer.huawei.com/consumer/en/doc/harmonyos-guides/app-linking-startup}{App Linking}
1001*/
1002bool QOhosAbilityContextImpl::tryOpenLink(const QString &link, std::shared_ptr<OpenLinkOptions> options)
1003{
1004 return tryOpenLinkImpl(
1005 m_instanceMainWindow, link,
1006 options
1007 ? static_cast<const QOhosOpenLinkOptionsImpl &>(*options).appLinkingOnly()
1008 : std::nullopt);
1009}
1010
1011/*!
1012 \fn virtual void QtHarmonyExtras::AbilityContext::setContinuationActive(bool continuationActive)
1013
1014 Sets the mission continuation state of the underlying Ability instance as per the
1015 \a continuationActive parameter (\c true = active, \c false = inactive).
1016
1017 See \l {https://developer.huawei.com/consumer/en/doc/harmonyos-references/js-apis-inner-application-uiabilitycontext#setmissioncontinuestate10-1}{setMissionContinueState}
1018*/
1019void QOhosAbilityContextImpl::setContinuationActive(bool continuationActive)
1020{
1021 setContinuationActiveImpl(m_instanceMainWindow, continuationActive);
1022}
1023
1024std::shared_ptr<OperationStatus> startAbilityImpl(
1025 const Want &want, std::optional<QOhosStartOptionsData> qpaStartOptions)
1026{
1027 auto wantJson = convertWantToJsonObject(want);
1028 bool success = QOhosJsThreadGateway::eval(
1029 [&](QOhosJsState &jsState) {
1030 auto optMainUiAbility = jsState.defaultQAbility();
1031 if (!optMainUiAbility.has_value())
1032 return false;
1033 auto mainUiAbility = optMainUiAbility.value();
1034 if (mainUiAbility.IsEmpty())
1035 return false;
1036
1037 auto arguments = std::vector<QNapi::ValueWrapper>{QtOhos::mapJsonObjectToNapiObject(jsState.env(), wantJson)};
1038 if (qpaStartOptions.has_value())
1039 arguments.push_back(convertStartOptionsToNapiObject(jsState, qpaStartOptions.value()));
1040
1041 mainUiAbility.eval("context.startAbility(*)", arguments);
1042
1043 // FIXME:
1044 // * there should be error code taken from a call to JS `startAbility` function
1045 // * error code should be checked and provided to the returned `operationStatus`
1046 return true;
1047 },
1048 Q_FUNC_INFO);
1049 return createOperationStatus(success);
1050}
1051
1052void startAppProcessImpl(
1053 const QString &processId, const Want &requestWant,
1054 std::optional<QOhosStartOptionsData> qpaStartOptions)
1055{
1056 auto requestWantJson = convertWantToJsonObject(requestWant);
1057 QOhosJsThreadGateway::invokeAndWaitForContinue(
1058 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
1059 auto startOptions = qpaStartOptions.has_value()
1060 ? convertStartOptionsToNapiObject(jsState, qpaStartOptions.value())
1061 : QNapi::Object();
1062
1063 auto sharedTaskPromise = QtOhos::moveToSharedPtr(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1064 jsState.startAppProcess(
1065 processId.toStdString(),
1066 QtOhos::mapJsonObjectToNapiObject(jsState.env(), requestWantJson),
1067 startOptions,
1068 [sharedTaskPromise](QOhosJsState &) {
1069 (*sharedTaskPromise)();
1070 });
1071 },
1072 Q_FUNC_INFO);
1073}
1074
1075}
1076
1077/*!
1078 \class QtHarmonyExtras::AbilityContext
1079 \inmodule QtHarmonyExtras
1080 \since 5.12.12
1081 \brief The AbilityContext class is to manage native UI Ability context. See
1082 \l {https://developer.huawei.com/consumer/en/doc/harmonyos-references-V5/js-apis-inner-application-uiabilitycontext-V5}
1083 {UIAbilityContext}.
1084*/
1085
1086/*!
1087 \fn void QtHarmonyExtras::AbilityContext::newWantInfoReceived(std::shared_ptr<QtHarmonyExtras::WantInfo> wantInfo)
1088
1089 Singal is emitted when an ability gets new \a want. See
1090 \l {https://developer.huawei.com/consumer/en/doc/harmonyos-references-V5/js-apis-app-ability-uiability-V5#uiabilityonnewwant}
1091 {On New Want}.
1092*/
1093
1094/*!
1095 \fn void QtHarmonyExtras::AbilityContext::continueRequestReceived(std::shared_ptr<QtHarmonyExtras::OnContinueContext> onContinueContext)
1096
1097 Signal emitted when the ability receives onContinue request. The signal delivers \a onContinueContext on which User
1098 can set onContinue response.
1099 See \l {https://developer.huawei.com/consumer/en/doc/harmonyos-references-V13/js-apis-app-ability-uiability-V13#uiabilityoncontinue}
1100 {UIAbility onContinue}.
1101
1102 \sa sendAgreeResponse(), sendMismatchResponse(), sendRejectResponse()
1103*/
1104
1113
1114AbilityContext::~AbilityContext() = default;
1115
1116/*!
1117 \fn AbilityContext *QtHarmonyExtras::AbilityContext::defaultInstance()
1118
1119 Returns instance of the class which is not connected to any specific Ability instance. It should
1120 be used when the application needs to perform some operations without selecting specific
1121 Ability instance (via the corresponding main window).
1122
1123 See descriptions of specific class methods for information about their behavior for the default
1124 instance.
1125
1126 The returned object is owned by QtHarmonyExtras and lives for the lifetime of the application;
1127 do not delete it.
1128*/
1133
1134/*!
1135 \fn AbilityContext *QtHarmonyExtras::AbilityContext::instanceForMainWindow(QWindow *instanceMainWindow)
1136
1137 Returns instance of the class which is connected to Ability instance identified by the
1138 \a instanceMainWindow. Methods called on the returned object will only affect the
1139 corresponding Ability instance.
1140
1141 \a instanceMainWindow must not be \c nullptr.
1142
1143 The returned object is owned by QtHarmonyExtras and remains valid while \a instanceMainWindow
1144 exists; do not delete it. Use QPointer to hold a reference that may outlive the window.
1145*/
1163
1164/*!
1165 \fn std::shared_ptr<OperationStatus> QtHarmonyExtras::startAbility(const Want &want, std::shared_ptr<StartOptions> options)
1166
1167 Starts an Ability for a given \a want and \a options; pass a null \a options to start without
1168 any start options. See
1169 \l {https://developer.huawei.com/consumer/en/doc/harmonyos-references-V5/js-apis-inner-application-uiabilitycontext-V5#uiabilitycontextstartability-1}
1170 {Start Ability}.
1171
1172 \warning Currently, operation status result is hardcoded as "successful" (even if ability were
1173 not started).
1174*/
1175std::shared_ptr<OperationStatus> startAbility(const Want &want, std::shared_ptr<StartOptions> options)
1176{
1177 return startAbilityImpl(want, options ? tryConvertStartOptionsToQpaFunctionsStruct(*options) : std::nullopt);
1178}
1179
1180/*!
1181 \fn std::shared_ptr<OperationStatus> QtHarmonyExtras::startAbilityByType(const QString &appType,
1182 const QJsonObject &wantParameters)
1183
1184 Starts an Ability for a given \a appType and \a wantParameters. See
1185 \l {https://developer.huawei.com/consumer/en/doc/harmonyos-references-V5/js-apis-inner-application-uiabilitycontext-V5#uiabilitycontextstartabilitybytype11-1}
1186 {Start Ability}.
1187
1188 \return true on success
1189*/
1190std::shared_ptr<OperationStatus> startAbilityByType(const QString &appType, const QJsonObject &wantParameters)
1191{
1192 bool success = startAbilityByTypeImpl(appType, wantParameters);
1193 return createOperationStatus(success);
1194}
1195
1196/*!
1197 Starts another instance of the UIAbility used by the Qt app with specified widget inside
1198
1199 The caller should pass newly created QWidget \a instanceWidget, without any setting any parent, calling show() or winId() on it.
1200*/
1201void startNewAbilityInstance(QWidget *instanceWidget)
1202{
1203 instanceWidget->show();
1204}
1205
1206/*!
1207 \fn void QtHarmonyExtras::startAppProcess(const QString &processId, const Want &requestWant, std::shared_ptr<StartOptions> options)
1208
1209 Starts application process for a given \a processId, \a requestWant and \a options; pass a null
1210 \a options to start without any start options.
1211*/
1212void startAppProcess(const QString &processId, const Want &requestWant, std::shared_ptr<StartOptions> options)
1213{
1214 startAppProcessImpl(processId, requestWant, options ? tryConvertStartOptionsToQpaFunctionsStruct(*options) : std::nullopt);
1215}
1216
1217/*!
1218 \fn void QtHarmonyExtras::setAbilityInstanceDestroyEnabled(QWindow *instanceWindow, bool destroyEnabled)
1219
1220 Sets whether the Ability related with \a instanceWindow can be automatically destroyed by the
1221 system when the user clicks on the window's "close" button. If \a destroyEnabled is \c true,
1222 the system destroys the Ability automatically (and Qt needs to adapt to this).
1223 If \a destroyEnabled = \c false, the window is not automatically destroyed, but instead standard
1224 Qt path for window close is triggered, i.e. QWindow::close().
1225
1226 By default, the flag is set to \c false.
1227
1228 \sa QtHarmonyExtras::AbilityContext::setDestroyFromSystemEnabled()
1229*/
1230void setAbilityInstanceDestroyEnabled(QWindow *instanceWindow, bool destroyEnabled)
1231{
1232 AbilityContext::instanceForMainWindow(instanceWindow)->setDestroyFromSystemEnabled(destroyEnabled);
1233}
1234
1235/*!
1236 \fn std::optional<QByteArray> tryGetOnContinueData(const Want &want)
1237
1238 Tries to get continuation / migration related data that was provided on the source device.
1239 Returns an empty optional if no such data found. The data is expected to be stored in the \a want parameters.
1240 See \l {https://developer.huawei.com/consumer/en/doc/harmonyos-guides/app-continuation-guide}
1241 {Application Continuation}.
1242*/
1244{
1245 auto key = QString::fromUtf8(qtOnContinueMigrationDataPropertyName);
1246 if (want.parameters.contains(key)) {
1247 auto base64String = want.parameters.value(key).toString();
1248 auto decodedData = QByteArray::fromBase64(base64String.toUtf8());
1249 return decodedData;
1250 } else {
1251 return {};
1252 }
1253}
1254
1255/*!
1256 \class QtHarmonyExtras::OnContinueContext
1257 \inmodule QtHarmonyExtras
1258 \since 5.12.12
1259 \brief The OnContinueContext class manages onContinue context. It provides system
1260 data, like source application version code and set the onContinue result that is requested by the system.
1261 See \l {https://developer.huawei.com/consumer/en/doc/harmonyos-references-V13/js-apis-app-ability-uiability-V13#uiabilityoncontinue}
1262 {UIAbility onContinue}.
1263*/
1266
1267OpenLinkOptions::OpenLinkOptions() = default;
1268OpenLinkOptions::~OpenLinkOptions() = default;
1269
1271{
1272 return std::make_shared<QOhosOpenLinkOptionsImpl>();
1273}
1274
1275}
1276
1277QT_END_NAMESPACE
void startAppProcess(const QString &processId, const Want &requestWant, std::shared_ptr< StartOptions > options)
Starts application process for a given processId, requestWant and options; pass a null options to sta...
std::shared_ptr< OpenLinkOptions > createOpenLinkOptions()
void startNewAbilityInstance(QWidget *instanceWidget)
Starts another instance of the UIAbility used by the Qt app with specified widget inside.
void setAbilityInstanceDestroyEnabled(QWindow *instanceWindow, bool destroyEnabled)
Sets whether the Ability related with instanceWindow can be automatically destroyed by the system whe...
std::shared_ptr< OperationStatus > startAbilityByType(const QString &appType, const QJsonObject &wantParameters)
Starts an Ability for a given appType and wantParameters.
std::optional< QByteArray > tryGetOnContinueData(const Want &want)
Tries to get continuation / migration related data that was provided on the source device.
std::shared_ptr< OperationStatus > startAbility(const Want &want, std::shared_ptr< StartOptions > options)
Starts an Ability for a given want and options; pass a null options to start without any start option...