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
qohossettings.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 <QtCore/private/qohoscommon_p.h>
6#include <cmath>
7#include <cstring>
8#include <functional>
9#include <optional>
10#include <qohosdeviceinfo_p.h>
11#include <qohosjsutils.h>
12#include <qohosplugincore.h>
13#include <qohosutils.h>
14#include <string>
15
17
18namespace {
19
20constexpr const char *fontSizeScalePropertyName = "font_scale";
21constexpr const char *windowPcModeSwitchStatusPropertyName = "window_pcmode_switch_status";
22
23std::optional<std::string> tryGetDataItemValue(const std::string &name, const std::string &domainName)
24{
25 return QtOhos::evalInJsThreadWithPromise<std::optional<std::string>>(
26 [&](QtOhos::JsState &jsState, auto evalPromise) {
27 auto optDefaultQAbility = jsState.defaultQAbility();
28 if (!optDefaultQAbility) {
29 evalPromise({});
30 return;
31 }
32
33 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
34 jsState.evalToPromiseOrRejectOnThrow(
35 "@ohos.settings.getValue(*)",
36 {optDefaultQAbility->get("context"), name, domainName})
37 .onThen([thenPromise = std::move(thenCatchPromises.first)](const QtOhos::CallbackInfo &cbInfo) {
38 std::string result = cbInfo.getFirstArg<QNapi::String>(Q_FUNC_INFO);
39 thenPromise(result);
40 })
41 .onCatch([catchPromise = std::move(thenCatchPromises.second), name, domainName](const QtOhos::CallbackInfo &) {
42 qOhosPrintfError(
43 "Got error from @ohos.settings.getValue(..., '%s', '%s').",
44 name.c_str(), domainName.c_str());
45 catchPromise({});
46 });
47 },
48 Q_FUNC_INFO);
49}
50
51template<typename T>
52std::optional<T> tryGetDataItemTypedValue(const std::string &name, const std::string &domainName);
53
54template<>
55std::optional<double> tryGetDataItemTypedValue(const std::string &name, const std::string &domainName)
56{
57 auto optStringValue = tryGetDataItemValue(name, domainName);
58 auto optDoubleValue = optStringValue.has_value()
59 ? QtOhos::tryParseStringAsFiniteDouble(optStringValue.value())
60 : std::nullopt;
61
62 if (optStringValue.has_value() && !optDoubleValue.has_value()) {
63 qOhosPrintfError(
64 "OHOS settings value %s/%s ('%s') is not correct double value, assuming empty setting",
65 name.c_str(), domainName.c_str(), optStringValue.value().c_str());
66 }
67
68 return optDoubleValue;
69}
70
72{
73 return QtOhos::evalInJsThread([](QtOhos::JsState &jsState) {
74 return jsState.eval<QNapi::String>("@ohos.settings.domainName.USER_PROPERTY").Utf8Value();
75 },
76 Q_FUNC_INFO);
77}
78
80{
81 return jsState.eval<QNapi::String>("@ohos.settings.domainName.USER_PROPERTY");
82}
83
85{
86 auto optQAbility = jsState.defaultQAbility();
87 return optQAbility
88 ? std::optional(optQAbility->eval<QNapi::Object>("context"))
89 : std::nullopt;
90}
91
93 QtOhos::JsState &jsState, const QNapi::Object &context, const std::string &name)
94{
95 return jsState.eval<QNapi::String>(
96 "@ohos.settings.getValueSync(*)",
97 {context, name, "", settingsUserPropertyDomainName(jsState)});
98}
99
101 QtOhos::JsState &jsState, QNapi::Object context, const std::string &name,
102 std::function<void(QtOhos::JsState &)> onChanged)
103{
104 const std::string domainName = settingsUserPropertyDomainName(jsState);
105
106 const bool registered = jsState.eval<QNapi::Boolean>(
107 "@ohos.settings.registerKeyObserver(*)",
108 {
109 context, name, domainName,
110 [onChanged = std::move(onChanged)](const QtOhos::CallbackInfo &cbInfo) {
111 onChanged(cbInfo.jsState());
112 }
113 });
114 if (!registered) {
115 qOhosPrintfWarning(
116 "Failed to register observer for settings key '%s' in domain '%s'.",
117 name.c_str(), domainName.c_str());
118 return nullptr;
119 }
120
121 auto contextRefPtr = QtOhos::moveToSharedPtr(QNapi::Reference<>::makePersistentFrom(context));
122 return std::shared_ptr<void>(
123 nullptr,
124 [contextRefPtr, name, domainName](auto) {
126 [&](QtOhos::JsState &jsState) {
127 auto contextRef = std::move(*contextRefPtr);
128 jsState.eval<QNapi::Value>(
129 "@ohos.settings.unregisterKeyObserver(*)",
130 {contextRef.Value(), name, domainName});
131 },
132 Q_FUNC_INFO);
133 });
134}
135
137{
138 auto optContext = settingsContext(jsState);
139 if (!optContext)
140 return false;
141
142 return readSettingValue(jsState, optContext.value(), windowPcModeSwitchStatusPropertyName) == "true";
143}
144
146{
148 return [] { return true; };
149
150 return QtOhos::makeDataSource<bool>(
152 [](QtOhos::JsState &jsState, QOhosConsumer<bool> valueChangedConsumer) -> std::shared_ptr<void> {
153 // FIXME: the observer must use the launching UIAbility's context. By
154 // API definition @ohos.settings does not accept the application
155 // context, and free-window state is not part of the app Configuration.
156 // That context can be destroyed while the process lives, orphaning the
157 // observer. The orphaned observer keeps firing (verified on device), so
158 // the cached value stays correct. Revisit when the platform exposes
159 // settings observation on the application context.
160 auto optContext = settingsContext(jsState);
161 if (!optContext)
162 return nullptr;
163
164 return registerSettingsKeyObserver(
165 jsState, optContext.value(), windowPcModeSwitchStatusPropertyName,
166 [valueChangedConsumer = std::move(valueChangedConsumer)](QtOhos::JsState &jsState) {
167 valueChangedConsumer(readWindowPcModeEnabled(jsState));
168 });
169 },
170 makeQOhosNoOpConsumer(),
171 QtOhos::invokeInQtThread,
172 Q_FUNC_INFO);
173}
174
176{
177 return [] {
178 return QOhosDeviceInfo::is2in1()
179 || QtOhos::evalInJsThread(readWindowPcModeEnabled, Q_FUNC_INFO);
180 };
181}
182
183}
184
186{
187 static QOhosSettings instance;
188 return instance;
189}
190
191std::shared_ptr<void> QOhosSettings::installSettingsCache()
192{
193 return QtOhos::makeDestroyNotifier(
194 [this, previousSupplier = std::exchange(m_windowPcModeEnabled, makeWindowPcModeEnabledSupplier())]() mutable {
195 m_windowPcModeEnabled = std::move(previousSupplier);
196 });
197}
198
199QOhosSettings::QOhosSettings()
200 : m_windowPcModeEnabled(makeUncachedWindowPcModeEnabledSupplier())
201{
202}
203
205{
206 constexpr double defaultFontSizeScale = 1.0;
207 const auto maybeFontSizeScaleSetting = tryGetDataItemTypedValue<double>(
209
210 if (!maybeFontSizeScaleSetting.has_value()) {
211 qOhosPrintfWarning(
212 "Cannot obtain '%s' property. Assuming its default fallback mode value %f",
213 fontSizeScalePropertyName, defaultFontSizeScale);
214 return defaultFontSizeScale;
215 }
216
217 return maybeFontSizeScaleSetting.value();
218}
219
221{
222 return m_windowPcModeEnabled();
223}
224
225QT_END_NAMESPACE
bool isWindowPcModeEnabled() const
static QOhosSettings & instance()
double fontSizeScale() const
Combined button and popup list for selecting options.
bool readWindowPcModeEnabled(QtOhos::JsState &jsState)
std::optional< std::string > tryGetDataItemValue(const std::string &name, const std::string &domainName)
constexpr const char * windowPcModeSwitchStatusPropertyName
QOhosSupplier< bool > makeWindowPcModeEnabledSupplier()
std::shared_ptr< void > registerSettingsKeyObserver(QtOhos::JsState &jsState, QNapi::Object context, const std::string &name, std::function< void(QtOhos::JsState &)> onChanged)
std::optional< QNapi::Object > settingsContext(QtOhos::JsState &jsState)
constexpr const char * fontSizeScalePropertyName
std::string getOhosSettingsUserPropertyDomainName()
std::optional< double > tryGetDataItemTypedValue(const std::string &name, const std::string &domainName)
std::optional< T > tryGetDataItemTypedValue(const std::string &name, const std::string &domainName)
QOhosSupplier< bool > makeUncachedWindowPcModeEnabledSupplier()
std::string settingsUserPropertyDomainName(QtOhos::JsState &jsState)
std::string readSettingValue(QtOhos::JsState &jsState, const QNapi::Object &context, const std::string &name)
void runInJsThreadAndWait(const std::function< void(JsState &)> &task, std::string callerContextName={})
std::optional< double > tryParseStringAsFiniteDouble(const std::string &inputString)