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
qohoswantinfo.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "qohosenums_p.h"
6#include "qohosjsenv_p.h"
7#include <QtCore/private/qcore_ohos_p.h>
8#include <QtCore/private/qnapi_p.h>
9#include <QtCore/private/qohoscommon_p.h>
10#include <QtCore/private/qohoslogger_p.h>
11#include <QtCore/qbytearray.h>
12#include <QtCore/qjsonobject.h>
13#include <QtCore/qlist.h>
14#include <QtCore/qstring.h>
15#include <QtCore/qvariant.h>
16#include <cstddef>
17#include <cstdint>
18#include <memory>
19#include <optional>
20#include <string>
21#include <vector>
22#include <database/udmf/udmf_meta.h>
23#include <database/udmf/utd.h>
24
25QT_BEGIN_NAMESPACE
26
27namespace QtOhosAppKit::Private {
28
29detail::WantInfoPriv::WantInfoPriv() = default;
30detail::WantInfoPriv::~WantInfoPriv() = default;
31
32namespace {
33
34template<typename T>
35std::optional<T> getOptionalProperty(const QNapi::Object &object, const std::string &propName)
36{
37 auto optPropValue = QNapi::getOptionalPropOrEmpty<T>(object, propName);
38 return !optPropValue.IsEmpty()
39 ? std::make_optional(optPropValue)
40 : std::nullopt;
41}
42
43std::optional<std::string> tryMapUtdTypeIdToMimeType(const std::string &utdTypeId)
44{
45 std::shared_ptr<::OH_Utd> utd(
46 ::OH_Utd_Create(utdTypeId.c_str()),
47 [](::OH_Utd *utd) {
48 if (utd != nullptr)
49 ::OH_Utd_Destroy(utd);
50 });
51
52 std::vector<std::string> mimeTypes;
53 if (utd) {
54 unsigned int typesCount = 0;
55 const char **rawMimeTypes = ::OH_Utd_GetMimeTypes(utd.get(), &typesCount);
56 if (rawMimeTypes == nullptr && typesCount != 0) {
57 qOhosReportFatalErrorAndAbort(
58 "%s: got inconsistent result from OH_Utd_GetMimeTypes() call: array is null, size is %u",
59 Q_FUNC_INFO, typesCount);
60 }
61 if (rawMimeTypes != nullptr)
62 mimeTypes = std::vector<std::string>(rawMimeTypes, rawMimeTypes + typesCount);
63 }
64
65 return !mimeTypes.empty()
66 ? std::make_optional(mimeTypes.front())
67 : std::nullopt;
68}
69
70std::optional<detail::SharedRecord> tryConvertNapiObjectToSharedRecord(QNapi::Object record)
71{
72 auto tryGetOptionalStringProp = [](const QNapi::Object &object, const std::string &propName) -> std::optional<QString> {
73 auto optProp = getOptionalProperty<QNapi::String>(object, propName);
74 return optProp.has_value()
75 ? std::make_optional(QString::fromStdString(optProp.value()))
76 : std::nullopt;
77 };
78
79 auto tryGetOptionalByteArrayProp = [](const QNapi::Object &object, const std::string &propName) -> std::optional<QByteArray> {
80 auto optProp = getOptionalProperty<QNapi::TypedArrayOf<std::uint8_t>>(object, propName);
81 return optProp.has_value()
82 ? std::make_optional(QByteArray(
83 reinterpret_cast<const char *>(optProp.value().Data()),
84 optProp.value().ByteLength()))
85 : std::nullopt;
86 };
87
88 auto tryGetOptionalJsonObjectProp = [](const QNapi::Object &object, const std::string &propName) -> std::optional<QJsonObject> {
89 auto optProp = getOptionalProperty<QNapi::Object>(object, propName);
90 return optProp.has_value()
91 ? std::make_optional(QOhosJsEnv::fromNapiValue<QJsonObject>(optProp.value()))
92 : std::nullopt;
93 };
94
95 std::string utd = record.get<QNapi::String>("utd");
96 auto optMimeType = utd != UDMF_META_HYPERLINK
97 ? tryMapUtdTypeIdToMimeType(utd)
98 : std::optional<std::string>("text/uri-list");
99 if (!optMimeType.has_value()) {
100 qOhosPrintfWarning(
101 "%s: can't map utd '%s' to mimetype, not mapping the record",
102 Q_FUNC_INFO, utd.c_str());
103 return std::nullopt;
104 }
105
106 auto content = tryGetOptionalStringProp(record, "content");
107 auto uri = tryGetOptionalStringProp(record, "uri");
108 if (!content.has_value() && !uri.has_value()) {
109 qOhosPrintfWarning(
110 "%s: cannot create Shared Record, content and uri properties are empty", Q_FUNC_INFO);
111 return std::nullopt;
112 }
113
114 auto optExtraDataJson = tryGetOptionalJsonObjectProp(record, "extraData");
115
116 return std::make_optional(
117 detail::SharedRecord{
118 .mimeType = QString::fromStdString(optMimeType.value()),
119 .content = content,
120 .filePath = uri,
121 .title = tryGetOptionalStringProp(record, "title"),
122 .label = tryGetOptionalStringProp(record, "label"),
123 .description = tryGetOptionalStringProp(record, "description"),
124 .thumbnail = tryGetOptionalByteArrayProp(record, "thumbnail"),
125 .thumbnailFilePath = tryGetOptionalStringProp(record, "thumbnailUri"),
126 .extraData = optExtraDataJson.has_value()
127 ? std::make_optional(optExtraDataJson.value().toVariantMap())
128 : std::nullopt,
129 });
130}
131
132std::optional<detail::WantInfoPriv::LaunchReason> tryMapOhosLaunchReasonToWantInfoEnum(
133 QtOhos::enums::ohos::app::ability::AbilityConstant::LaunchReason ohosLaunchReason)
134{
135 using OhosLaunchReason = QtOhos::enums::ohos::app::ability::AbilityConstant::LaunchReason;
136 using WantInfoPriv = detail::WantInfoPriv;
137
138 switch (ohosLaunchReason) {
139 case OhosLaunchReason::START_ABILITY:
140 return std::make_optional(WantInfoPriv::LaunchReason::START_ABILITY);
141 case OhosLaunchReason::CONTINUATION:
142 return std::make_optional(WantInfoPriv::LaunchReason::CONTINUATION);
143 case OhosLaunchReason::PREPARE_CONTINUATION:
144 return std::make_optional(WantInfoPriv::LaunchReason::PREPARE_CONTINUATION);
145 case OhosLaunchReason::PRELOAD:
146 return std::make_optional(WantInfoPriv::LaunchReason::PRELOAD);
147 case OhosLaunchReason::UNKNOWN:
148 case OhosLaunchReason::CALL:
149 case OhosLaunchReason::APP_RECOVERY:
150 case OhosLaunchReason::SHARE:
151 case OhosLaunchReason::AUTO_STARTUP:
152 case OhosLaunchReason::INSIGHT_INTENT:
153 return std::make_optional(WantInfoPriv::LaunchReason::UNKNOWN);
154 }
155
156 return {};
157}
158
159detail::WantInfoPriv::LaunchReason mapJsLaunchReasonToWantInfoEnumWithFallback(
160 QOhosJsState &jsState, QNapi::Number jsLaunchReason)
161{
162 auto optLaunchReasonJsEnum =
163 jsState.tryMapOhosEnumFromJs<QtOhos::enums::ohos::app::ability::AbilityConstant::LaunchReason>(jsLaunchReason);
164 auto optLaunchReason =
165 optLaunchReasonJsEnum.has_value()
166 ? tryMapOhosLaunchReasonToWantInfoEnum(optLaunchReasonJsEnum.value())
167 : std::nullopt;
168 return optLaunchReason.value_or(detail::WantInfoPriv::LaunchReason::UNKNOWN);
169}
170
171class WantInfoImpl : public detail::WantInfoPriv
172{
173public:
174 WantInfoImpl(QNapi::Object want, LaunchReason launchReason);
175
176 QJsonObject jsonObject() const override;
177
178 std::optional<QList<detail::SharedRecord>> tryGetSharedDataRecords() const override;
179
180 std::optional<ContactInfo> tryGetContactInfo() const override;
181
182 LaunchReason launchReason() const override;
183
184private:
185 struct JsScopeData
186 {
187 QNapi::Reference<QNapi::Object> want;
188 };
189
190 std::shared_ptr<JsScopeData> m_jsScopeData;
191 QJsonObject m_jsonObject;
192 LaunchReason m_launchReason;
193};
194
195WantInfoImpl::WantInfoImpl(QNapi::Object want, LaunchReason launchReason)
197 , m_jsScopeData(
198 QtOhos::makeProxyWithJsThreadDeleter(
199 QtOhos::moveToSharedPtr(
200 JsScopeData {
201 .want = QNapi::Reference<>::makePersistentFrom(want),
202 })))
203 , m_jsonObject(QOhosJsEnv::fromNapiValue<QJsonObject>(want))
204 , m_launchReason(launchReason)
205{
206}
207
208QJsonObject WantInfoImpl::jsonObject() const
209{
210 return m_jsonObject;
211}
212
213std::optional<QList<detail::SharedRecord>> WantInfoImpl::tryGetSharedDataRecords() const
214{
215 using SharedRecord = detail::SharedRecord;
216
217 return QOhosJsThreadGateway::evalWithPromise<std::optional<QList<SharedRecord>>>(
218 [&](QOhosJsState &jsState, QOhosTaskPromise<std::optional<QList<SharedRecord>>> evalPromise) {
219 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
220 jsState.evalToPromiseOrRejectOnThrow(
221 "@kit.ShareKit.systemShare.getSharedData(*)", {m_jsScopeData->want.Value()})
222 .onThen(
223 [thenPromise = std::move(thenCatchPromises.first)](const QOhosCallbackInfo &cbInfo) {
224 QNapi::Object sharedData = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
225
226 auto optRecords = QNapi::getArrayElements<QList<std::optional<SharedRecord>>, QNapi::Object>(
227 sharedData.eval<QNapi::Array>("getRecords()"), &tryConvertNapiObjectToSharedRecord);
228
229 QList<SharedRecord> records;
230 for (const auto &optRecord : optRecords) {
231 if (optRecord.has_value())
232 records.append(optRecord.value());
233 }
234
235 std::size_t unconvertedRecordsCount = optRecords.size() - records.size();
236 if (unconvertedRecordsCount != 0) {
237 qOhosPrintfWarning(
238 "%s: can't convert %zu Shared Records, ignoring them",
239 Q_FUNC_INFO, unconvertedRecordsCount);
240 }
241
242 thenPromise(std::make_optional(records));
243 })
244 .onCatch(
245 [catchPromise = std::move(thenCatchPromises.second)](const QOhosCallbackInfo &cbInfo) {
246 QtOhos::logJsCallbackError(cbInfo, "@kit.ShareKit.systemShare.getSharedData() failed");
247 catchPromise(std::nullopt);
248 });
249 },
250 Q_FUNC_INFO);
251}
252
253std::optional<detail::WantInfoPriv::ContactInfo> WantInfoImpl::tryGetContactInfo() const
254{
255 using ContactInfo = detail::WantInfoPriv::ContactInfo;
256
257 return QOhosJsThreadGateway::evalWithPromise<std::optional<ContactInfo>>(
258 [&](QOhosJsState &jsState, QOhosTaskPromise<std::optional<ContactInfo>> evalPromise) {
259 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
260 jsState.evalToPromiseOrRejectOnThrow(
261 "@kit.ShareKit.systemShare.getContactInfo(*)", {m_jsScopeData->want.Value()})
262 .onThen(
263 [thenPromise = std::move(thenCatchPromises.first)](const QOhosCallbackInfo &cbInfo) {
264 auto contactInfoObj = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
265 ContactInfo contactInfo = {
266 .contactType = QString::fromStdString(
267 contactInfoObj.get<QNapi::String>("contactType")),
268 .contactId = QString::fromStdString(
269 contactInfoObj.get<QNapi::String>("contactId")),
270 };
271 thenPromise(std::make_optional(contactInfo));
272 })
273 .onCatch(
274 [catchPromise = std::move(thenCatchPromises.second)](const QOhosCallbackInfo &cbInfo) {
275 QtOhos::logJsCallbackError(cbInfo, "@kit.ShareKit.systemShare.getContactInfo() failed");
276 catchPromise(std::nullopt);
277 });
278 },
279 Q_FUNC_INFO);
280}
281
282detail::WantInfoPriv::LaunchReason WantInfoImpl::launchReason() const
283{
284 return m_launchReason;
285}
286
287}
288
290{
291 return QOhosJsThreadGateway::eval(
292 [](QOhosJsState &jsState) {
293 auto optAppLaunchParam = jsState.optAppLaunchParam();
294 auto optAppLaunchReason = optAppLaunchParam.has_value()
295 ? std::make_optional(mapJsLaunchReasonToWantInfoEnumWithFallback(
296 jsState, optAppLaunchParam.value().get<QNapi::Number>("launchReason")))
297 : std::nullopt;
298 auto appLaunchReason = optAppLaunchReason.value_or(detail::WantInfoPriv::LaunchReason::UNKNOWN);
299 return QSharedPointer<WantInfoImpl>::create(jsState.appLaunchWant(), appLaunchReason);
300 },
301 Q_FUNC_INFO);
302}
303
304void addNewWantConsumer(QObject *context, QOhosConsumer<QJsonObject> wantConsumer)
305{
306 auto sharedWantConsumer = QtOhos::moveToSharedPtr(std::move(wantConsumer));
307 addNewWantConsumer(
308 context,
309 [sharedWantConsumer](QSharedPointer<detail::WantInfoPriv> wantInfo) {
310 (*sharedWantConsumer)(wantInfo->jsonObject());
311 });
312}
313
315 QObject *context, QOhosConsumer<QSharedPointer<detail::WantInfoPriv>> wantConsumer)
316{
317 auto contextRef = QtOhos::makeQThreadSafeRef(context);
318 auto sharedWantConsumer = QtOhos::moveToSharedPtr(std::move(wantConsumer));
319 QOhosJsThreadGateway::runAndWait(
320 [&](QOhosJsState &jsState) {
321 jsState.addNewWantConsumer(
322 [contextRef, sharedWantConsumer](QOhosJsState &jsState, QNapi::Object napiWant, QNapi::Object launchParam) {
323 auto launchReason = mapJsLaunchReasonToWantInfoEnumWithFallback(
324 jsState, launchParam.get<QNapi::Number>("launchReason"));
325 auto wantInfo = QSharedPointer<WantInfoImpl>::create(napiWant, launchReason);
326 contextRef.visitInQtThreadIfAlive(
327 [sharedWantConsumer, wantInfo](auto &) {
328 (*sharedWantConsumer)(wantInfo);
329 });
330 });
331 },
332 Q_FUNC_INFO);
333}
334
335}
336
337QT_END_NAMESPACE
QSharedPointer< detail::WantInfoPriv > makeAppLaunchWantInfo()
void addNewWantConsumer(QObject *context, QOhosConsumer< QJsonObject > wantConsumer)