Skip to content

Commit

Permalink
Use SupportedLocalesIterator to read ReadSupportedLocales from Device…
Browse files Browse the repository at this point in the history
…InfoProvider (#16950)
  • Loading branch information
yufengwangca authored and pull[bot] committed Jan 10, 2024
1 parent 0ddb321 commit 2656709
Show file tree
Hide file tree
Showing 12 changed files with 183 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <app/util/attribute-storage.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/DeviceInfoProvider.h>
#include <platform/PlatformManager.h>

using namespace chip;
Expand Down Expand Up @@ -57,18 +58,32 @@ LocalizationConfigurationAttrAccess gAttrAccess;
CHIP_ERROR LocalizationConfigurationAttrAccess::ReadSupportedLocales(AttributeValueEncoder & aEncoder)
{
CHIP_ERROR err = CHIP_NO_ERROR;
DeviceLayer::AttributeList<CharSpan, DeviceLayer::kMaxLanguageTags> supportedLocales;

if (DeviceLayer::PlatformMgr().GetSupportedLocales(supportedLocales) == CHIP_NO_ERROR)
DeviceLayer::DeviceInfoProvider * provider = DeviceLayer::GetDeviceInfoProvider();

if (provider)
{
err = aEncoder.EncodeList([&supportedLocales](const auto & encoder) -> CHIP_ERROR {
for (const Span<const char> & locale : supportedLocales)
{
ReturnErrorOnFailure(encoder.Encode(locale));
}
DeviceLayer::DeviceInfoProvider::SupportedLocalesIterator * it = provider->IterateSupportedLocales();

if (it)
{
err = aEncoder.EncodeList([&it](const auto & encoder) -> CHIP_ERROR {
CharSpan activeLocale;

while (it->Next(activeLocale))
{
ReturnErrorOnFailure(encoder.Encode(activeLocale));
}

return CHIP_NO_ERROR;
});
return CHIP_NO_ERROR;
});

it->Release();
}
else
{
err = aEncoder.EncodeEmptyList();
}
}
else
{
Expand Down Expand Up @@ -102,17 +117,23 @@ using Status = Protocols::InteractionModel::Status;
static Protocols::InteractionModel::Status emberAfPluginLocalizationConfigurationOnActiveLocaleChange(EndpointId EndpointId,
CharSpan newLangtag)
{
DeviceLayer::AttributeList<CharSpan, DeviceLayer::kMaxLanguageTags> supportedLocales;
DeviceLayer::DeviceInfoProvider * provider = DeviceLayer::GetDeviceInfoProvider();
DeviceLayer::DeviceInfoProvider::SupportedLocalesIterator * it;

if (DeviceLayer::PlatformMgr().GetSupportedLocales(supportedLocales) == CHIP_NO_ERROR)
if (provider && (it = provider->IterateSupportedLocales()))
{
for (const Span<const char> & locale : supportedLocales)
CharSpan outLocale;

while (it->Next(outLocale))
{
if (locale.data_equal(newLangtag))
if (outLocale.data_equal(newLangtag))
{
it->Release();
return Status::Success;
}
}

it->Release();
}

return Status::InvalidValue;
Expand Down Expand Up @@ -141,32 +162,58 @@ Protocols::InteractionModel::Status MatterLocalizationConfigurationClusterServer

void emberAfLocalizationConfigurationClusterServerInitCallback(EndpointId endpoint)
{
DeviceLayer::AttributeList<CharSpan, DeviceLayer::kMaxLanguageTags> supportedLocales;
CharSpan validLocale;

char outBuffer[Attributes::ActiveLocale::TypeInfo::MaxLength()];
MutableCharSpan activeLocale(outBuffer);
char outBuf[Attributes::ActiveLocale::TypeInfo::MaxLength()];
MutableCharSpan activeLocale(outBuf);
EmberAfStatus status = ActiveLocale::Get(endpoint, activeLocale);

VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(Zcl, "Failed to read ActiveLocale with error: 0x%02x", status));

// We could have an invalid ActiveLocale value if an OTA update removed support for the value we were using.
if (DeviceLayer::PlatformMgr().GetSupportedLocales(supportedLocales) == CHIP_NO_ERROR)
DeviceLayer::DeviceInfoProvider * provider = DeviceLayer::GetDeviceInfoProvider();

VerifyOrReturn(provider != nullptr, ChipLogError(Zcl, "DeviceInfoProvider is not registered"));

DeviceLayer::DeviceInfoProvider::SupportedLocalesIterator * it = provider->IterateSupportedLocales();

if (it)
{
for (const Span<const char> & locale : supportedLocales)
CHIP_ERROR err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;

char tempBuf[Attributes::ActiveLocale::TypeInfo::MaxLength()];
MutableCharSpan validLocale(tempBuf);
CharSpan outLocale;
bool validLocaleCached = false;

while (it->Next(outLocale))
{
if (locale.data_equal(activeLocale))
if (outLocale.data_equal(activeLocale))
{
return;
err = CHIP_NO_ERROR;
break;
}

validLocale = locale;
if (!validLocaleCached)
{
if (CopyCharSpanToMutableCharSpan(outLocale, validLocale) != CHIP_NO_ERROR)
{
err = CHIP_ERROR_WRITE_FAILED;
break;
}
else
{
validLocaleCached = true;
}
}
}

// If initial value is not one of the allowed values, pick one valid value and write it.
status = ActiveLocale::Set(endpoint, validLocale);
VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status,
ChipLogError(Zcl, "Failed to write active locale with error: 0x%02x", status));
it->Release();

if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
{
// If initial value is not one of the allowed values, write the valid value it.
status = ActiveLocale::Set(endpoint, validLocale);
VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status,
ChipLogError(Zcl, "Failed to write active locale with error: 0x%02x", status));
}
}
}

Expand Down
14 changes: 12 additions & 2 deletions src/include/platform/DeviceInfoProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace DeviceLayer {
static constexpr size_t kMaxUserLabelListLength = 10;
static constexpr size_t kMaxLabelNameLength = 16;
static constexpr size_t kMaxLabelValueLength = 16;
static constexpr size_t kMaxActiveLocaleLength = 35;

class DeviceInfoProvider
{
Expand Down Expand Up @@ -66,8 +67,9 @@ class DeviceInfoProvider
using FixedLabelType = app::Clusters::FixedLabel::Structs::LabelStruct::Type;
using UserLabelType = app::Clusters::UserLabel::Structs::LabelStruct::Type;

using FixedLabelIterator = Iterator<FixedLabelType>;
using UserLabelIterator = Iterator<UserLabelType>;
using FixedLabelIterator = Iterator<FixedLabelType>;
using UserLabelIterator = Iterator<UserLabelType>;
using SupportedLocalesIterator = Iterator<CharSpan>;

DeviceInfoProvider() = default;

Expand All @@ -91,6 +93,14 @@ class DeviceInfoProvider
virtual FixedLabelIterator * IterateFixedLabel(EndpointId endpoint) = 0;
virtual UserLabelIterator * IterateUserLabel(EndpointId endpoint) = 0;

/**
* Creates an iterator that may be used to obtain the list of supported locales of the device.
* In order to release the allocated memory, the Release() method must be called after the iteration is finished.
* @retval An instance of EndpointIterator on success
* @retval nullptr if no iterator instances are available.
*/
virtual SupportedLocalesIterator * IterateSupportedLocales() = 0;

protected:
/**
* @brief Set the UserLabel at the specified index of the UserLabelList on a given endpoint
Expand Down
7 changes: 0 additions & 7 deletions src/include/platform/PlatformManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class DiscoveryImplPlatform;

namespace DeviceLayer {

static constexpr size_t kMaxLanguageTags = 254; // Maximum number of entry type 'ARRAY' supports
static constexpr size_t kMaxCalendarTypes = 12;

class PlatformManagerImpl;
Expand Down Expand Up @@ -193,7 +192,6 @@ class PlatformManager
bool IsChipStackLockedByCurrentThread() const;
#endif

CHIP_ERROR GetSupportedLocales(AttributeList<chip::CharSpan, kMaxLanguageTags> & supportedLocales);
CHIP_ERROR GetSupportedCalendarTypes(
AttributeList<app::Clusters::TimeFormatLocalization::CalendarType, kMaxCalendarTypes> & supportedCalendarTypes);

Expand Down Expand Up @@ -449,11 +447,6 @@ inline CHIP_ERROR PlatformManager::StartChipTimer(System::Clock::Timeout duratio
return static_cast<ImplClass *>(this)->_StartChipTimer(duration);
}

inline CHIP_ERROR PlatformManager::GetSupportedLocales(AttributeList<chip::CharSpan, kMaxLanguageTags> & supportedLocales)
{
return static_cast<ImplClass *>(this)->_GetSupportedLocales(supportedLocales);
}

inline CHIP_ERROR PlatformManager::GetSupportedCalendarTypes(
AttributeList<app::Clusters::TimeFormatLocalization::CalendarType, kMaxCalendarTypes> & supportedCalendarTypes)
{
Expand Down
8 changes: 0 additions & 8 deletions src/include/platform/internal/GenericPlatformManagerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ class GenericPlatformManagerImpl
void _ScheduleWork(AsyncWorkFunct workFunct, intptr_t arg);
void _DispatchEvent(const ChipDeviceEvent * event);

CHIP_ERROR _GetSupportedLocales(AttributeList<chip::CharSpan, kMaxLanguageTags> & supportedLocales);
CHIP_ERROR _GetSupportedCalendarTypes(
AttributeList<app::Clusters::TimeFormatLocalization::CalendarType, kMaxCalendarTypes> & supportedCalendarTypes);

Expand All @@ -79,13 +78,6 @@ class GenericPlatformManagerImpl
// Instruct the compiler to instantiate the template only when explicitly told to do so.
extern template class GenericPlatformManagerImpl<PlatformManagerImpl>;

template <class ImplClass>
inline CHIP_ERROR
GenericPlatformManagerImpl<ImplClass>::_GetSupportedLocales(AttributeList<chip::CharSpan, kMaxLanguageTags> & supportedLocales)
{
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

template <class ImplClass>
inline CHIP_ERROR GenericPlatformManagerImpl<ImplClass>::_GetSupportedCalendarTypes(
AttributeList<app::Clusters::TimeFormatLocalization::CalendarType, kMaxCalendarTypes> & supportedCalendarTypes)
Expand Down
11 changes: 11 additions & 0 deletions src/lib/support/Span.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,15 @@ inline CHIP_ERROR CopySpanToMutableSpan(ByteSpan span_to_copy, MutableByteSpan &
return CHIP_NO_ERROR;
}

inline CHIP_ERROR CopyCharSpanToMutableCharSpan(CharSpan cspan_to_copy, MutableCharSpan & out_buf)
{
VerifyOrReturnError(IsSpanUsable(cspan_to_copy), CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(out_buf.size() >= cspan_to_copy.size(), CHIP_ERROR_BUFFER_TOO_SMALL);

memcpy(out_buf.data(), cspan_to_copy.data(), cspan_to_copy.size());
out_buf.reduce_size(cspan_to_copy.size());

return CHIP_NO_ERROR;
}

} // namespace chip
17 changes: 0 additions & 17 deletions src/platform/Darwin/PlatformManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,23 +136,6 @@ CHIP_ERROR PlatformManagerImpl::_PostEvent(const ChipDeviceEvent * event)
return CHIP_NO_ERROR;
}

CHIP_ERROR
PlatformManagerImpl::_GetSupportedLocales(AttributeList<chip::CharSpan, kMaxLanguageTags> & supportedLocales)
{
// In Darwin simulation, return following hardcoded list of Strings that are valid values for the ActiveLocale.
supportedLocales.add(CharSpan::fromCharString("Test"));
supportedLocales.add(CharSpan::fromCharString("en-US"));
supportedLocales.add(CharSpan::fromCharString("de-DE"));
supportedLocales.add(CharSpan::fromCharString("fr-FR"));
supportedLocales.add(CharSpan::fromCharString("en-GB"));
supportedLocales.add(CharSpan::fromCharString("es-ES"));
supportedLocales.add(CharSpan::fromCharString("zh-CN"));
supportedLocales.add(CharSpan::fromCharString("it-IT"));
supportedLocales.add(CharSpan::fromCharString("ja-JP"));

return CHIP_NO_ERROR;
}

CHIP_ERROR
PlatformManagerImpl::_GetSupportedCalendarTypes(
AttributeList<app::Clusters::TimeFormatLocalization::CalendarType, kMaxCalendarTypes> & supportedCalendarTypes)
Expand Down
1 change: 0 additions & 1 deletion src/platform/Darwin/PlatformManagerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener
CHIP_ERROR _StartEventLoopTask();
CHIP_ERROR _StopEventLoopTask();

CHIP_ERROR _GetSupportedLocales(AttributeList<chip::CharSpan, kMaxLanguageTags> & supportedLocales);
CHIP_ERROR _GetSupportedCalendarTypes(
AttributeList<app::Clusters::TimeFormatLocalization::CalendarType, kMaxCalendarTypes> & supportedCalendarTypes);

Expand Down
71 changes: 71 additions & 0 deletions src/platform/Linux/DeviceInfoProviderImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,5 +196,76 @@ bool DeviceInfoProviderImpl::UserLabelIteratorImpl::Next(UserLabelType & output)
}
}

DeviceInfoProvider::SupportedLocalesIterator * DeviceInfoProviderImpl::IterateSupportedLocales()
{
return new SupportedLocalesIteratorImpl();
}

size_t DeviceInfoProviderImpl::SupportedLocalesIteratorImpl::Count()
{
// In Linux Simulation, return the size of the hardcoded list of Strings that are valid values for the ActiveLocale.
// {("en-US"), ("de-DE"), ("fr-FR"), ("en-GB"), ("es-ES"), ("zh-CN"), ("it-IT"), ("ja-JP")}

return 8;
}

bool DeviceInfoProviderImpl::SupportedLocalesIteratorImpl::Next(CharSpan & output)
{
// In Linux simulation, return following hardcoded list of Strings that are valid values for the ActiveLocale.
CHIP_ERROR err = CHIP_NO_ERROR;

const char * activeLocalePtr = nullptr;

VerifyOrReturnError(mIndex < 8, false);

switch (mIndex)
{
case 0:
activeLocalePtr = "en-US";
break;
case 1:
activeLocalePtr = "de-DE";
break;
case 2:
activeLocalePtr = "fr-FR";
break;
case 3:
activeLocalePtr = "en-GB";
break;
case 4:
activeLocalePtr = "es-ES";
break;
case 5:
activeLocalePtr = "zh-CN";
break;
case 6:
activeLocalePtr = "it-IT";
break;
case 7:
activeLocalePtr = "ja-JP";
break;
default:
err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
break;
}

if (err == CHIP_NO_ERROR)
{
VerifyOrReturnError(std::strlen(activeLocalePtr) <= kMaxActiveLocaleLength, false);

Platform::CopyString(mActiveLocaleBuf, kMaxActiveLocaleLength + 1, activeLocalePtr);

output = CharSpan::fromCharString(mActiveLocaleBuf);

mIndex++;

return true;
}
else
{
return false;
}
}

} // namespace DeviceLayer
} // namespace chip
14 changes: 14 additions & 0 deletions src/platform/Linux/DeviceInfoProviderImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class DeviceInfoProviderImpl : public DeviceInfoProvider
// Iterators
FixedLabelIterator * IterateFixedLabel(EndpointId endpoint) override;
UserLabelIterator * IterateUserLabel(EndpointId endpoint) override;
SupportedLocalesIterator * IterateSupportedLocales() override;

static DeviceInfoProviderImpl & GetDefaultInstance();

Expand Down Expand Up @@ -66,6 +67,19 @@ class DeviceInfoProviderImpl : public DeviceInfoProvider
char mUserLabelValueBuf[kMaxLabelValueLength + 1];
};

class SupportedLocalesIteratorImpl : public SupportedLocalesIterator
{
public:
SupportedLocalesIteratorImpl() = default;
size_t Count() override;
bool Next(CharSpan & output) override;
void Release() override { delete this; }

private:
size_t mIndex = 0;
char mActiveLocaleBuf[kMaxActiveLocaleLength + 1];
};

CHIP_ERROR SetUserLabelLength(EndpointId endpoint, size_t val) override;
CHIP_ERROR GetUserLabelLength(EndpointId endpoint, size_t & val) override;
CHIP_ERROR SetUserLabelAt(EndpointId endpoint, size_t index, const UserLabelType & userLabel) override;
Expand Down
Loading

0 comments on commit 2656709

Please sign in to comment.