diff --git a/docs/openrpc/openrpc/localization.json b/docs/openrpc/openrpc/localization.json index 632f70f..77ad905 100644 --- a/docs/openrpc/openrpc/localization.json +++ b/docs/openrpc/openrpc/localization.json @@ -118,6 +118,39 @@ } } ] + }, + { + "name": "timeZone", + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:time-zone" + ] + } + ], + "summary": "Get the IANA timezone of the device.", + "params": [], + "result": { + "name": "timeZone", + "summary": "The device timezone.", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "Default Result", + "value": "America/New_York" + } + } + ] } ], "components": { diff --git a/docs/openrpc/the-spec/firebolt-open-rpc.json b/docs/openrpc/the-spec/firebolt-open-rpc.json index 698d4f1..3cc029f 100644 --- a/docs/openrpc/the-spec/firebolt-open-rpc.json +++ b/docs/openrpc/the-spec/firebolt-open-rpc.json @@ -1087,6 +1087,39 @@ } ] }, + { + "name": "Localization.timeZone", + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:time-zone" + ] + } + ], + "summary": "Get the IANA timezone of the device.", + "params": [], + "result": { + "name": "timeZone", + "summary": "The device timezone.", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "Default Result", + "value": "America/New_York" + } + } + ] + }, { "name": "Metrics.ready", "tags": [ @@ -3396,6 +3429,52 @@ } } }, + { + "name": "Localization.onTimeZoneChanged", + "tags": [ + { + "name": "event", + "x-notifier": "Localization.onTimeZoneChanged", + "x-subscriber-for": "Localization.timeZone" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:time-zone" + ] + } + ], + "summary": "Get the IANA timezone of the device.", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, { "name": "Network.onConnectedChanged", "summary": "Returns whether the device currently has a usable network connection.", @@ -4040,4 +4119,4 @@ } } } -} \ No newline at end of file +} diff --git a/include/firebolt/localization.h b/include/firebolt/localization.h index 3eb9dc3..976bb41 100644 --- a/include/firebolt/localization.h +++ b/include/firebolt/localization.h @@ -81,6 +81,22 @@ class ILocalization virtual Result subscribeOnPresentationLanguageChanged(std::function&& notification) = 0; + /** + * @brief Get the IANA timezone of the device. + * + * @retval The device timezone or error + */ + virtual Result timeZone() const = 0; + + /** + * @brief Subscribe on the change of TimeZoneChanged property + * + * @param[in] notification : The callback function + * + * @retval The subscriptionId or error + */ + virtual Result subscribeOnTimeZoneChanged(std::function&& notification) = 0; + /** * @brief Remove subscriber from subscribers list. This method is generic for * all subscriptions diff --git a/src/localization_impl.cpp b/src/localization_impl.cpp index 454363f..b4c733b 100644 --- a/src/localization_impl.cpp +++ b/src/localization_impl.cpp @@ -43,6 +43,17 @@ Result LocalizationImpl::presentationLanguage() const return helper_.get("Localization.presentationLanguage"); } +Result LocalizationImpl::timeZone() const +{ + return helper_.get("Localization.timeZone"); +} + +Result LocalizationImpl::subscribeOnTimeZoneChanged(std::function&& notification) +{ + return subscriptionManager_.subscribe("Localization.onTimeZoneChanged", + std::move(notification)); +} + Result LocalizationImpl::subscribeOnCountryChanged(std::function&& notification) { return subscriptionManager_.subscribe("Localization.onCountryChanged", diff --git a/src/localization_impl.h b/src/localization_impl.h index 80e7cf5..eb9df69 100644 --- a/src/localization_impl.h +++ b/src/localization_impl.h @@ -36,6 +36,7 @@ class LocalizationImpl : public ILocalization Result country() const override; Result> preferredAudioLanguages() const override; Result presentationLanguage() const override; + Result timeZone() const override; // Events Result subscribeOnCountryChanged(std::function&& notification) override; @@ -43,6 +44,7 @@ class LocalizationImpl : public ILocalization std::function&)>&& notification) override; Result subscribeOnPresentationLanguageChanged(std::function&& notification) override; + Result subscribeOnTimeZoneChanged(std::function&& notification) override; Result unsubscribe(SubscriptionId id) override; void unsubscribeAll() override; diff --git a/test/component/localizationTest.cpp b/test/component/localizationTest.cpp index 3f6a228..8953072 100644 --- a/test/component/localizationTest.cpp +++ b/test/component/localizationTest.cpp @@ -145,3 +145,40 @@ TEST_F(LocalizationCTest, subscribeOnPreferredPresentationLanguageChanged) auto result = Firebolt::IFireboltAccessor::Instance().LocalizationInterface().unsubscribe(id.value_or(0)); ASSERT_TRUE(result) << "error on unsubscribe "; } + +TEST_F(LocalizationCTest, TimeZone) +{ + auto result = Firebolt::IFireboltAccessor::Instance().LocalizationInterface().timeZone(); + ASSERT_TRUE(result) << "error on get"; + + auto expectedValue = jsonEngine.get_value("Localization.timeZone").get(); + EXPECT_EQ(*result, expectedValue); +} + +TEST_F(LocalizationCTest, subscribeOnTimeZoneChanged) +{ + auto id = Firebolt::IFireboltAccessor::Instance().LocalizationInterface().subscribeOnTimeZoneChanged( + [&](const std::string& timeZone) + { + EXPECT_EQ(timeZone, "America/New_York"); + { + std::lock_guard lock(mtx); + eventReceived = true; + } + cv.notify_one(); + }); + + ASSERT_TRUE(id) << "error on subscribe "; + EXPECT_TRUE(id.has_value()) << "error on id"; + + // Trigger the event from the mock server + triggerEvent("Localization.onTimeZoneChanged", R"({"value":"America/New_York"})"); + verifyEventReceived(mtx, cv, eventReceived); + + SetUp(); + triggerEvent("Localization.onTimeZoneChanged", R"({"value":12345})"); + verifyEventNotReceived(mtx, cv, eventReceived); + + auto result = Firebolt::IFireboltAccessor::Instance().LocalizationInterface().unsubscribe(id.value_or(0)); + ASSERT_TRUE(result) << "error on unsubscribe "; +} diff --git a/test/unit/localizationTest.cpp b/test/unit/localizationTest.cpp index fb1eaeb..29a5f69 100644 --- a/test/unit/localizationTest.cpp +++ b/test/unit/localizationTest.cpp @@ -113,3 +113,31 @@ TEST_F(LocalizationUTest, subscribeOnPresentationLanguageChanged) auto result = localizationImpl_.unsubscribe(id.value_or(0)); ASSERT_TRUE(result) << "error on unsubscribe "; } + +TEST_F(LocalizationUTest, TimeZone) +{ + auto expectedValue = jsonEngine.get_value("Localization.timeZone").get(); + mock("Localization.timeZone"); + + auto result = localizationImpl_.timeZone(); + ASSERT_TRUE(result) << "error on get"; + + EXPECT_EQ(*result, expectedValue); +} + +TEST_F(LocalizationUTest, TimeZoneBadResponse) +{ + mock_with_response("Localization.timeZone", 12345); + ASSERT_FALSE(localizationImpl_.timeZone()) << "LocalizationImpl::timeZone() did not return an error"; +} + +TEST_F(LocalizationUTest, subscribeOnTimeZoneChanged) +{ + mockSubscribe("Localization.onTimeZoneChanged"); + + auto id = localizationImpl_.subscribeOnTimeZoneChanged([](auto) {}); + ASSERT_TRUE(id) << "error on subscribe "; + EXPECT_TRUE(id.has_value()) << "error on id"; + auto result = localizationImpl_.unsubscribe(id.value_or(0)); + ASSERT_TRUE(result) << "error on unsubscribe "; +}