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