Move DeviceInfoProvider to common code and use it in linux and NRF. (#18687)

* Add and use DeviceInfoProvider for Zephyr. nrfconnect and telink use this

* Restyle

* Make code compile

* Switch new/delete to platform new/delete

* Start moving DeviceInfoProviderImpl into a common example file that all examples can use. Expect other applications to replace these and override

* Add a readme for the directory regarding providers folder

* Make nrf compile with the example providers for the lighting app

* Make sure linux app build also compiles with SetDeviceInfoProvider

* Restyle

* Remove Zephyr from comments

* Update date for license blurb
diff --git a/examples/lighting-app/nrfconnect/main/AppTask.cpp b/examples/lighting-app/nrfconnect/main/AppTask.cpp
index 12ee2a9..9ee6c8e 100644
--- a/examples/lighting-app/nrfconnect/main/AppTask.cpp
+++ b/examples/lighting-app/nrfconnect/main/AppTask.cpp
@@ -24,6 +24,7 @@
 #include "PWMDevice.h"
 #include "ThreadUtil.h"
 
+#include <DeviceInfoProviderImpl.h>
 #include <app-common/zap-generated/attribute-id.h>
 #include <app-common/zap-generated/attribute-type.h>
 #include <app-common/zap-generated/attributes/Accessors.h>
@@ -81,6 +82,8 @@
 bool sIsThreadEnabled     = false;
 bool sHaveBLEConnections  = false;
 
+chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider;
+
 } // namespace
 
 AppTask AppTask::sAppTask;
@@ -173,6 +176,7 @@
 
     static chip::CommonCaseDeviceServerInitParams initParams;
     (void) initParams.InitializeStaticResourcesBeforeServerInit();
+    chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider);
 
     ReturnErrorOnFailure(chip::Server::GetInstance().Init(initParams));
 #if CONFIG_CHIP_OTA_REQUESTOR
diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp
index 83f867f..26fea11 100644
--- a/examples/platform/linux/AppMain.cpp
+++ b/examples/platform/linux/AppMain.cpp
@@ -41,6 +41,8 @@
 #include <platform/CommissionableDataProvider.h>
 #include <platform/DiagnosticDataProvider.h>
 
+#include <DeviceInfoProviderImpl.h>
+
 #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
 #include "CommissionerMain.h"
 #include <ControllerShellCommands.h>
@@ -96,6 +98,8 @@
 // To hold SPAKE2+ verifier, discriminator, passcode
 LinuxCommissionableDataProvider gCommissionableDataProvider;
 
+chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider;
+
 #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
 chip::trace::TraceStream * gTraceStream = nullptr;
 #endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
@@ -236,6 +240,7 @@
     err = chip::examples::InitCommissionableDataProvider(gCommissionableDataProvider, LinuxDeviceOptions::GetInstance());
     SuccessOrExit(err);
     DeviceLayer::SetCommissionableDataProvider(&gCommissionableDataProvider);
+    DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider);
 
     err = chip::examples::InitConfigurationManager(reinterpret_cast<ConfigurationManagerImpl &>(ConfigurationMgr()),
                                                    LinuxDeviceOptions::GetInstance());
diff --git a/examples/platform/linux/BUILD.gn b/examples/platform/linux/BUILD.gn
index d1be2f2..71586b0 100644
--- a/examples/platform/linux/BUILD.gn
+++ b/examples/platform/linux/BUILD.gn
@@ -51,6 +51,7 @@
   }
 
   public_deps = [
+    "${chip_root}/examples/providers:device_info_provider",
     "${chip_root}/src/app/server",
     "${chip_root}/src/credentials:default_attestation_verifier",
     "${chip_root}/src/lib",
diff --git a/examples/providers/BUILD.gn b/examples/providers/BUILD.gn
new file mode 100644
index 0000000..244f70d
--- /dev/null
+++ b/examples/providers/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright (c) 2022 Project CHIP Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build_overrides/build.gni")
+import("//build_overrides/chip.gni")
+
+config("include_providers_dir") {
+  include_dirs = [ "." ]
+}
+
+static_library("device_info_provider") {
+  output_name = "libMatterDeviceInfoProviderExample"
+  output_dir = "${root_out_dir}/lib"
+
+  sources = [
+    "DeviceInfoProviderImpl.cpp",
+    "DeviceInfoProviderImpl.h",
+  ]
+
+  public_deps = [
+    "${chip_root}/src/lib/support",
+    "${chip_root}/src/platform",
+  ]
+
+  public_configs = [ ":include_providers_dir" ]
+}
diff --git a/examples/providers/DeviceInfoProviderImpl.cpp b/examples/providers/DeviceInfoProviderImpl.cpp
new file mode 100644
index 0000000..ba06435
--- /dev/null
+++ b/examples/providers/DeviceInfoProviderImpl.cpp
@@ -0,0 +1,366 @@
+/*
+ *
+ *    Copyright (c) 2022 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+#include <DeviceInfoProviderImpl.h>
+
+#include <lib/core/CHIPTLV.h>
+#include <lib/support/CHIPMemString.h>
+#include <lib/support/CodeUtils.h>
+#include <lib/support/DefaultStorageKeyAllocator.h>
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <cstring>
+
+namespace chip {
+namespace DeviceLayer {
+
+namespace {
+constexpr TLV::Tag kLabelNameTag  = TLV::ContextTag(0);
+constexpr TLV::Tag kLabelValueTag = TLV::ContextTag(1);
+} // anonymous namespace
+
+DeviceInfoProviderImpl & DeviceInfoProviderImpl::GetDefaultInstance()
+{
+    static DeviceInfoProviderImpl sInstance;
+    return sInstance;
+}
+
+DeviceInfoProvider::FixedLabelIterator * DeviceInfoProviderImpl::IterateFixedLabel(EndpointId endpoint)
+{
+    return chip::Platform::New<FixedLabelIteratorImpl>(endpoint);
+}
+
+DeviceInfoProviderImpl::FixedLabelIteratorImpl::FixedLabelIteratorImpl(EndpointId endpoint) : mEndpoint(endpoint)
+{
+    mIndex = 0;
+}
+
+size_t DeviceInfoProviderImpl::FixedLabelIteratorImpl::Count()
+{
+    // A hardcoded labelList on all endpoints.
+    return 4;
+}
+
+bool DeviceInfoProviderImpl::FixedLabelIteratorImpl::Next(FixedLabelType & output)
+{
+    bool retval = true;
+
+    // A hardcoded list for testing only
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    const char * labelPtr = nullptr;
+    const char * valuePtr = nullptr;
+
+    VerifyOrReturnError(mIndex < 4, false);
+
+    ChipLogProgress(DeviceLayer, "Get the fixed label with index:%u at endpoint:%d", static_cast<unsigned>(mIndex), mEndpoint);
+
+    switch (mIndex)
+    {
+    case 0:
+        labelPtr = "room";
+        valuePtr = "bedroom 2";
+        break;
+    case 1:
+        labelPtr = "orientation";
+        valuePtr = "North";
+        break;
+    case 2:
+        labelPtr = "floor";
+        valuePtr = "2";
+        break;
+    case 3:
+        labelPtr = "direction";
+        valuePtr = "up";
+        break;
+    default:
+        err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
+        break;
+    }
+
+    if (err == CHIP_NO_ERROR)
+    {
+        VerifyOrReturnError(std::strlen(labelPtr) <= kMaxLabelNameLength, false);
+        VerifyOrReturnError(std::strlen(valuePtr) <= kMaxLabelValueLength, false);
+
+        Platform::CopyString(mFixedLabelNameBuf, kMaxLabelNameLength + 1, labelPtr);
+        Platform::CopyString(mFixedLabelValueBuf, kMaxLabelValueLength + 1, valuePtr);
+
+        output.label = CharSpan::fromCharString(mFixedLabelNameBuf);
+        output.value = CharSpan::fromCharString(mFixedLabelValueBuf);
+
+        mIndex++;
+
+        retval = true;
+    }
+    else
+    {
+        retval = false;
+    }
+
+    return retval;
+}
+
+CHIP_ERROR DeviceInfoProviderImpl::SetUserLabelLength(EndpointId endpoint, size_t val)
+{
+    DefaultStorageKeyAllocator keyAlloc;
+
+    return mStorage->SyncSetKeyValue(keyAlloc.UserLabelLengthKey(endpoint), &val, static_cast<uint16_t>(sizeof(val)));
+}
+
+CHIP_ERROR DeviceInfoProviderImpl::GetUserLabelLength(EndpointId endpoint, size_t & val)
+{
+    DefaultStorageKeyAllocator keyAlloc;
+    uint16_t len = static_cast<uint16_t>(sizeof(val));
+
+    return mStorage->SyncGetKeyValue(keyAlloc.UserLabelLengthKey(endpoint), &val, len);
+}
+
+CHIP_ERROR DeviceInfoProviderImpl::SetUserLabelAt(EndpointId endpoint, size_t index, const UserLabelType & userLabel)
+{
+    DefaultStorageKeyAllocator keyAlloc;
+    uint8_t buf[UserLabelTLVMaxSize()];
+    TLV::TLVWriter writer;
+    writer.Init(buf);
+
+    TLV::TLVType outerType;
+    ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerType));
+    ReturnErrorOnFailure(writer.PutString(kLabelNameTag, userLabel.label));
+    ReturnErrorOnFailure(writer.PutString(kLabelValueTag, userLabel.value));
+    ReturnErrorOnFailure(writer.EndContainer(outerType));
+
+    return mStorage->SyncSetKeyValue(keyAlloc.UserLabelIndexKey(endpoint, index), buf,
+                                     static_cast<uint16_t>(writer.GetLengthWritten()));
+}
+
+DeviceInfoProvider::UserLabelIterator * DeviceInfoProviderImpl::IterateUserLabel(EndpointId endpoint)
+{
+    return chip::Platform::New<UserLabelIteratorImpl>(*this, endpoint);
+}
+
+DeviceInfoProviderImpl::UserLabelIteratorImpl::UserLabelIteratorImpl(DeviceInfoProviderImpl & provider, EndpointId endpoint) :
+    mProvider(provider), mEndpoint(endpoint)
+{
+    size_t total = 0;
+
+    ReturnOnFailure(mProvider.GetUserLabelLength(mEndpoint, total));
+    mTotal = total;
+    mIndex = 0;
+}
+
+bool DeviceInfoProviderImpl::UserLabelIteratorImpl::Next(UserLabelType & output)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    VerifyOrReturnError(mIndex < mTotal, false);
+
+    DefaultStorageKeyAllocator keyAlloc;
+    uint8_t buf[UserLabelTLVMaxSize()];
+    uint16_t len = static_cast<uint16_t>(sizeof(buf));
+
+    err = mProvider.mStorage->SyncGetKeyValue(keyAlloc.UserLabelIndexKey(mEndpoint, mIndex), buf, len);
+    VerifyOrReturnError(err == CHIP_NO_ERROR, false);
+
+    TLV::ContiguousBufferTLVReader reader;
+    reader.Init(buf);
+    err = reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag());
+    VerifyOrReturnError(err == CHIP_NO_ERROR, false);
+
+    TLV::TLVType containerType;
+    VerifyOrReturnError(reader.EnterContainer(containerType) == CHIP_NO_ERROR, false);
+
+    chip::CharSpan label;
+    chip::CharSpan value;
+
+    VerifyOrReturnError(reader.Next(kLabelNameTag) == CHIP_NO_ERROR, false);
+    VerifyOrReturnError(reader.Get(label) == CHIP_NO_ERROR, false);
+
+    VerifyOrReturnError(reader.Next(kLabelValueTag) == CHIP_NO_ERROR, false);
+    VerifyOrReturnError(reader.Get(value) == CHIP_NO_ERROR, false);
+
+    VerifyOrReturnError(reader.VerifyEndOfContainer() == CHIP_NO_ERROR, false);
+    VerifyOrReturnError(reader.ExitContainer(containerType) == CHIP_NO_ERROR, false);
+
+    Platform::CopyString(mUserLabelNameBuf, label);
+    Platform::CopyString(mUserLabelValueBuf, value);
+
+    output.label = CharSpan::fromCharString(mUserLabelNameBuf);
+    output.value = CharSpan::fromCharString(mUserLabelValueBuf);
+
+    mIndex++;
+
+    return true;
+}
+
+DeviceInfoProvider::SupportedLocalesIterator * DeviceInfoProviderImpl::IterateSupportedLocales()
+{
+    return chip::Platform::New<SupportedLocalesIteratorImpl>();
+}
+
+size_t DeviceInfoProviderImpl::SupportedLocalesIteratorImpl::Count()
+{
+    // Hardcoded list of locales
+    // {("en-US"), ("de-DE"), ("fr-FR"), ("en-GB"), ("es-ES"), ("zh-CN"), ("it-IT"), ("ja-JP")}
+
+    return 8;
+}
+
+bool DeviceInfoProviderImpl::SupportedLocalesIteratorImpl::Next(CharSpan & output)
+{
+    bool retval = true;
+
+    // Hardcoded list of locales
+    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++;
+
+        retval = true;
+    }
+    else
+    {
+        retval = false;
+    }
+
+    return retval;
+}
+
+DeviceInfoProvider::SupportedCalendarTypesIterator * DeviceInfoProviderImpl::IterateSupportedCalendarTypes()
+{
+    return chip::Platform::New<SupportedCalendarTypesIteratorImpl>();
+}
+
+size_t DeviceInfoProviderImpl::SupportedCalendarTypesIteratorImpl::Count()
+{
+    // Hardcoded list of strings
+    // {("kBuddhist"), ("kChinese"), ("kCoptic"), ("kEthiopian"), ("kGregorian"), ("kHebrew"), ("kIndian"), ("kJapanese"),
+    //  ("kKorean"), ("kPersian"), ("kTaiwanese"), ("kIslamic")}
+
+    return 12;
+}
+
+bool DeviceInfoProviderImpl::SupportedCalendarTypesIteratorImpl::Next(CalendarType & output)
+{
+    bool retval = true;
+
+    // Hardcoded list of Strings that are valid values for the Calendar Types.
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    VerifyOrReturnError(mIndex < 12, false);
+
+    switch (mIndex)
+    {
+    case 0:
+        output = app::Clusters::TimeFormatLocalization::CalendarType::kBuddhist;
+        break;
+    case 1:
+        output = app::Clusters::TimeFormatLocalization::CalendarType::kChinese;
+        break;
+    case 2:
+        output = app::Clusters::TimeFormatLocalization::CalendarType::kCoptic;
+        break;
+    case 3:
+        output = app::Clusters::TimeFormatLocalization::CalendarType::kEthiopian;
+        break;
+    case 4:
+        output = app::Clusters::TimeFormatLocalization::CalendarType::kGregorian;
+        break;
+    case 5:
+        output = app::Clusters::TimeFormatLocalization::CalendarType::kHebrew;
+        break;
+    case 6:
+        output = app::Clusters::TimeFormatLocalization::CalendarType::kIndian;
+        break;
+    case 7:
+        output = app::Clusters::TimeFormatLocalization::CalendarType::kJapanese;
+        break;
+    case 8:
+        output = app::Clusters::TimeFormatLocalization::CalendarType::kKorean;
+        break;
+    case 9:
+        output = app::Clusters::TimeFormatLocalization::CalendarType::kPersian;
+        break;
+    case 10:
+        output = app::Clusters::TimeFormatLocalization::CalendarType::kTaiwanese;
+        break;
+    case 11:
+        output = app::Clusters::TimeFormatLocalization::CalendarType::kIslamic;
+        break;
+    default:
+        err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
+        break;
+    }
+
+    if (err == CHIP_NO_ERROR)
+    {
+        mIndex++;
+        retval = true;
+    }
+    else
+    {
+        retval = false;
+    }
+
+    return retval;
+}
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/examples/providers/DeviceInfoProviderImpl.h b/examples/providers/DeviceInfoProviderImpl.h
new file mode 100644
index 0000000..fc58436
--- /dev/null
+++ b/examples/providers/DeviceInfoProviderImpl.h
@@ -0,0 +1,106 @@
+/*
+ *
+ *    Copyright (c) 2022 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+#pragma once
+
+#include <lib/support/EnforceFormat.h>
+#include <platform/DeviceInfoProvider.h>
+
+namespace chip {
+namespace DeviceLayer {
+
+class DeviceInfoProviderImpl : public DeviceInfoProvider
+{
+public:
+    DeviceInfoProviderImpl() = default;
+    ~DeviceInfoProviderImpl() override {}
+
+    // Iterators
+    FixedLabelIterator * IterateFixedLabel(EndpointId endpoint) override;
+    UserLabelIterator * IterateUserLabel(EndpointId endpoint) override;
+    SupportedLocalesIterator * IterateSupportedLocales() override;
+    SupportedCalendarTypesIterator * IterateSupportedCalendarTypes() override;
+
+    static DeviceInfoProviderImpl & GetDefaultInstance();
+
+protected:
+    class FixedLabelIteratorImpl : public FixedLabelIterator
+    {
+    public:
+        FixedLabelIteratorImpl(EndpointId endpoint);
+        size_t Count() override;
+        bool Next(FixedLabelType & output) override;
+        void Release() override { chip::Platform::Delete(this); }
+
+    private:
+        EndpointId mEndpoint = 0;
+        size_t mIndex        = 0;
+        char mFixedLabelNameBuf[kMaxLabelNameLength + 1];
+        char mFixedLabelValueBuf[kMaxLabelValueLength + 1];
+    };
+
+    class UserLabelIteratorImpl : public UserLabelIterator
+    {
+    public:
+        UserLabelIteratorImpl(DeviceInfoProviderImpl & provider, EndpointId endpoint);
+        size_t Count() override { return mTotal; }
+        bool Next(UserLabelType & output) override;
+        void Release() override { chip::Platform::Delete(this); }
+
+    private:
+        DeviceInfoProviderImpl & mProvider;
+        EndpointId mEndpoint = 0;
+        size_t mIndex        = 0;
+        size_t mTotal        = 0;
+        char mUserLabelNameBuf[kMaxLabelNameLength + 1];
+        char mUserLabelValueBuf[kMaxLabelValueLength + 1];
+    };
+
+    class SupportedLocalesIteratorImpl : public SupportedLocalesIterator
+    {
+    public:
+        SupportedLocalesIteratorImpl() = default;
+        size_t Count() override;
+        bool Next(CharSpan & output) override;
+        void Release() override { chip::Platform::Delete(this); }
+
+    private:
+        size_t mIndex = 0;
+        char mActiveLocaleBuf[kMaxActiveLocaleLength + 1];
+    };
+
+    class SupportedCalendarTypesIteratorImpl : public SupportedCalendarTypesIterator
+    {
+    public:
+        SupportedCalendarTypesIteratorImpl() = default;
+        size_t Count() override;
+        bool Next(CalendarType & output) override;
+        void Release() override { chip::Platform::Delete(this); }
+
+    private:
+        size_t mIndex = 0;
+    };
+
+    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;
+
+private:
+    static constexpr size_t UserLabelTLVMaxSize() { return TLV::EstimateStructOverhead(kMaxLabelNameLength, kMaxLabelValueLength); }
+};
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/examples/providers/README.md b/examples/providers/README.md
new file mode 100644
index 0000000..dc0ccce
--- /dev/null
+++ b/examples/providers/README.md
@@ -0,0 +1,9 @@
+# Contents
+
+This folder contains example implementations of 'providers' that are generally
+application-specific. Final applications should generally have their own
+implementations of these
+
+## Device Info Provider
+
+Supports device-specific information like labels, locales and calendar types.