diff --git a/packages/device_info_plus/CHANGELOG.md b/packages/device_info_plus/CHANGELOG.md index 2b01e3a8a..129e7b1b4 100644 --- a/packages/device_info_plus/CHANGELOG.md +++ b/packages/device_info_plus/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.4.3 + +* Add `DeviceInfoPluginTizen.duid` to retrieve the device's DUID (Device Unique ID). +* Add 2 integration test cases. + ## 1.4.2 * Add an `implements` entry to the pubspec to improve discoverability on pub.dev. diff --git a/packages/device_info_plus/README.md b/packages/device_info_plus/README.md index 743cbe5be..3dd668766 100644 --- a/packages/device_info_plus/README.md +++ b/packages/device_info_plus/README.md @@ -10,7 +10,7 @@ Add `device_info_plus_tizen` as a dependency in your `pubspec.yaml` file. ```yaml dependencies: - device_info_plus_tizen: ^1.4.2 + device_info_plus_tizen: ^1.4.3 ``` Then you can import `device_info_plus_tizen` in your Dart code. @@ -26,31 +26,32 @@ String modelName = tizenInfo.modelName; ## Supported properties -| Property | Feature or system key | -|-|-| -| `modelName` | `http://tizen.org/system/model_name` | -| `cpuArch` | `http://tizen.org/feature/platform.core.cpu.arch` | -| `nativeApiVersion` | `http://tizen.org/feature/platform.native.api.version` | -| `platformVersion` | `http://tizen.org/feature/platform.version` | -| `webApiVersion` | `http://tizen.org/feature/platform.web.api.version` | -| `profile` | `http://tizen.org/feature/profile` | -| `buildDate` | `http://tizen.org/system/build.date` | -| `buildId` | `http://tizen.org/system/build.id` | -| `buildString` | `http://tizen.org/system/build.string` | -| `buildTime` | `http://tizen.org/system/build.time` | -| `buildType` | `http://tizen.org/system/build.type` | -| `buildVariant` | `http://tizen.org/system/build.variant` | -| `buildRelease` | `http://tizen.org/system/build.release` | -| `deviceType` | `http://tizen.org/system/device_type` | -| `manufacturer` | `http://tizen.org/system/manufacturer` | -| `platformName` | `http://tizen.org/system/platform.name` | -| `platformProcessor` | `http://tizen.org/system/platform.processor` | -| `tizenId` | `http://tizen.org/system/tizenid` | -| `freeDiskSize` | `storage_get_internal_memory_size()` | -| `totalDiskSize` | `storage_get_internal_memory_size()` | -| `physicalRamSize` | `runtime_info_get_system_memory_info()` | -| `availableRamSize` | `runtime_info_get_system_memory_info()` | -| `screenWidth` | `http://tizen.org/feature/screen.width` | -| `screenHeight` | `http://tizen.org/feature/screen.height` | +| Property | Feature or system key | TV only | +|-|-|-| +| `modelName` | `http://tizen.org/system/model_name` | | +| `cpuArch` | `http://tizen.org/feature/platform.core.cpu.arch` | | +| `nativeApiVersion` | `http://tizen.org/feature/platform.native.api.version` | | +| `platformVersion` | `http://tizen.org/feature/platform.version` | | +| `webApiVersion` | `http://tizen.org/feature/platform.web.api.version` | | +| `profile` | `http://tizen.org/feature/profile` | | +| `buildDate` | `http://tizen.org/system/build.date` | | +| `buildId` | `http://tizen.org/system/build.id` | | +| `buildString` | `http://tizen.org/system/build.string` | | +| `buildTime` | `http://tizen.org/system/build.time` | | +| `buildType` | `http://tizen.org/system/build.type` | | +| `buildVariant` | `http://tizen.org/system/build.variant` | | +| `buildRelease` | `http://tizen.org/system/build.release` | | +| `deviceType` | `http://tizen.org/system/device_type` | | +| `manufacturer` | `http://tizen.org/system/manufacturer` | | +| `platformName` | `http://tizen.org/system/platform.name` | | +| `platformProcessor` | `http://tizen.org/system/platform.processor` | | +| `tizenId` | `http://tizen.org/system/tizenid` | | +| `freeDiskSize` | `storage_get_internal_memory_size()` | | +| `totalDiskSize` | `storage_get_internal_memory_size()` | | +| `physicalRamSize` | `runtime_info_get_system_memory_info()` | | +| `availableRamSize` | `runtime_info_get_system_memory_info()` | | +| `screenWidth` | `http://tizen.org/feature/screen.width` | | +| `screenHeight` | `http://tizen.org/feature/screen.height` | | +| `duid` | `db/comss/duid` (vconf) | ✅ | For descriptions of the `system_info` keys in the list, see https://docs.tizen.org/application/native/guides/device/system. diff --git a/packages/device_info_plus/example/integration_test/device_info_plus_test.dart b/packages/device_info_plus/example/integration_test/device_info_plus_test.dart index c0bb63f33..294ce1f84 100644 --- a/packages/device_info_plus/example/integration_test/device_info_plus_test.dart +++ b/packages/device_info_plus/example/integration_test/device_info_plus_test.dart @@ -77,4 +77,26 @@ void main() { expect(rebuilt.screenWidth, tizenInfo.screenWidth); expect(rebuilt.totalDiskSize, tizenInfo.totalDiskSize); }, skip: !Platform.isLinux); + + // Tizen-only: duid has no upstream counterpart in device_info_plus. + test('duid does not throw', () async { + final deviceInfoPlugin = DeviceInfoPluginTizen(); + await deviceInfoPlugin.duid; + }, skip: !Platform.isLinux); + + test('duid is consistent and cached across repeated calls', () async { + // Repeated calls on the same instance return the cached instance. + final plugin1 = DeviceInfoPluginTizen(); + final first = await plugin1.duid; + final second = await plugin1.duid; + expect(second, first); + if (first != null) { + expect(second, same(first)); + } + + // A new instance triggers a fresh native call that must yield the same data. + final plugin2 = DeviceInfoPluginTizen(); + final third = await plugin2.duid; + expect(third, first); + }, skip: !Platform.isLinux); } diff --git a/packages/device_info_plus/example/lib/main.dart b/packages/device_info_plus/example/lib/main.dart index 5ccb31410..c2c1977a3 100644 --- a/packages/device_info_plus/example/lib/main.dart +++ b/packages/device_info_plus/example/lib/main.dart @@ -44,6 +44,7 @@ class _MyAppState extends State { try { deviceData = _readTizenDeviceInfo(await deviceInfoPlugin.tizenInfo); + deviceData['duid'] = await deviceInfoPlugin.duid; } on PlatformException { deviceData = { 'Error:': 'Failed to get platform version.', diff --git a/packages/device_info_plus/lib/device_info_plus_tizen.dart b/packages/device_info_plus/lib/device_info_plus_tizen.dart index a88c6626b..787164391 100644 --- a/packages/device_info_plus/lib/device_info_plus_tizen.dart +++ b/packages/device_info_plus/lib/device_info_plus_tizen.dart @@ -165,6 +165,11 @@ class _MethodChannelDeviceInfo { )).cast(), ); } + + /// The DUID (Device Unique ID) of this device. + Future getDuid() async { + return channel.invokeMethod('getDuid'); + } } /// Provides device and operating system information of a Tizen device. @@ -183,4 +188,13 @@ class DeviceInfoPluginTizen { /// See: https://docs.tizen.org/application/native/guides/device/system Future get tizenInfo async => _cachedTizenDeviceInfo ??= await _platform.tizenInfo(); + + /// This information does not change from call to call. Cache it. + String? _cachedDuid; + + /// The DUID (Device Unique ID) that uniquely identifies this device. + /// + /// Empty if the device isn't running the TV profile. Null if the + /// underlying vconf key couldn't be read (retrying may succeed). + Future get duid async => _cachedDuid ??= await _platform.getDuid(); } diff --git a/packages/device_info_plus/pubspec.yaml b/packages/device_info_plus/pubspec.yaml index 264f96238..09917faa0 100644 --- a/packages/device_info_plus/pubspec.yaml +++ b/packages/device_info_plus/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin providing detailed information about Tizen device (make, model, etc.) the app is running on. homepage: https://github.com/flutter-tizen/plugins repository: https://github.com/flutter-tizen/plugins/tree/main/packages/device_info_plus -version: 1.4.2 +version: 1.4.3 environment: sdk: ^3.7.0 diff --git a/packages/device_info_plus/tizen/src/device_info_plus_tizen_plugin.cc b/packages/device_info_plus/tizen/src/device_info_plus_tizen_plugin.cc index 986bc9baa..bdad88dde 100644 --- a/packages/device_info_plus/tizen/src/device_info_plus_tizen_plugin.cc +++ b/packages/device_info_plus/tizen/src/device_info_plus_tizen_plugin.cc @@ -4,6 +4,9 @@ #include "device_info_plus_tizen_plugin.h" +#ifdef TV_PROFILE +#include +#endif #include #include #include @@ -15,6 +18,7 @@ #include #include #include +#include #include #include "log.h" @@ -23,6 +27,40 @@ namespace { constexpr int64_t kUnknownMetric = -1; +// Returns nullopt only for a transient vconf read failure; a non-TV profile +// (permanent, not transient) returns an empty string instead. +std::optional GetDuid() { +#ifndef TV_PROFILE + return std::string(); +#else + using FuncVconfGetStr = char *(*)(const char *); + + void *handle = dlopen("libvconf.so.0", RTLD_LAZY); + if (!handle) { + LOG_ERROR("Failed to open libvconf.so.0."); + return std::nullopt; + } + + auto vconf_get_str = + reinterpret_cast(dlsym(handle, "vconf_get_str")); + if (!vconf_get_str) { + LOG_ERROR("Failed to find the vconf_get_str symbol."); + dlclose(handle); + return std::nullopt; + } + + char *value = vconf_get_str("db/comss/duid"); + dlclose(handle); + if (!value) { + LOG_ERROR("Failed to read db/comss/duid."); + return std::nullopt; + } + std::string duid = value; + free(value); + return duid; +#endif +} + class DeviceInfoPlusTizenPlugin : public flutter::Plugin { public: static void RegisterWithRegistrar(flutter::PluginRegistrar *registrar) { @@ -53,6 +91,13 @@ class DeviceInfoPlusTizenPlugin : public flutter::Plugin { if (method_name == "getTizenDeviceInfo") { result->Success(flutter::EncodableValue(GetTizenDeviceInfo())); + } else if (method_name == "getDuid") { + std::optional duid = GetDuid(); + if (duid.has_value()) { + result->Success(flutter::EncodableValue(*duid)); + } else { + result->Success(flutter::EncodableValue()); + } } else { result->NotImplemented(); }