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