Skip to content

refactor!: rebuild SamsungHealthReporter on the Samsung Health Data SDK - #3

Merged
kvs-coder merged 12 commits into
masterfrom
vk/health-data-sdk-migration
Oct 9, 2026
Merged

kvs-coder merged 12 commits into
masterfrom
vk/health-data-sdk-migration

Conversation

@kvs-coder

@kvs-coder kvs-coder commented Oct 9, 2026 •

Copy link
Copy Markdown
Owner

Summary

Rebuilds the library on the Samsung Health Data SDK 1.1.0 (the old Samsung Health SDK for Android was deprecated on 31.07.2025) with the HealthKitReporter architecture: one SamsungHealthReporter with a reader, writer, observer and manager, library-owned types and @Serializable payloads, suspend API, no SDK types in the public API. Breaking: releases as 1.0.0.

Changes

  • library/: facade, services, 25 HealthTypes, 20 Aggregations, 15 sample payloads + UserProfile, 67 unit tests, api/library.api
  • samsung-health-data-stub/: never-published stand-in for the login-gated, non-redistributable SDK AAR
  • app/: Jetpack Compose demo with a row per public call, plus permission diagnostics
  • Build: Gradle 8.14, AGP 8.13.2, Kotlin 2.2.21, ktlint, detekt, Kover, binary-compatibility-validator; CI + release-please; CI fetches the real AAR from the private kvs-coder/samsung-health-sdk repo with a read-only deploy key
  • Docs: AGENTS.md (+ CLAUDE.md), README with migration table, CONTRIBUTING, ADRs 0001–0003, ISSUE-*.md
  • Removed the 0.0.x sources, the 1.4.0 SDK jar and tracked .idea/

Tests

  • Unit tests: 67 executed, 0 failed, against the real SDK AAR and the stub; coverage 98.3% (Kover gate 98)
  • ktlint / detekt / Android lint: clean
  • apiCheck: passes, library.api committed
  • Example app build: passes; on a Pixel 7a (Samsung Health 7.00.6, developer mode) all 25 read permissions are granted and device/profile reads return real data; writes fail with SDK error 2003 until Samsung's partnership access code is entered

Samsung deprecated the Samsung Health SDK for Android on 31.07.2025 (end of
service 2028). This rebuilds the library on the Samsung Health Data SDK 1.1.0
with the HealthKitReporter architecture: one SamsungHealthReporter facade
sharing one HealthDataStore between a reader, writer, observer and manager,
library-owned types and @serializable payloads, suspend-first API, and no SDK
type in the public API. The SDK AAR is login-gated and not redistributable:
the library compiles against library/libs/*.aar when present, otherwise
against a never-published stub written from the API reference.

Changes:
- library/src/main/kotlin: facade, SamsungHealthException, services
  (read, readPage, userProfile, aggregate, insert, update, delete, changes,
  observe, permissions, resolve, devices), 25 HealthTypes, 20 Aggregations,
  15 sample payloads + UserProfile, value enums, decorators
- library/src/test/kotlin: 67 tests (payload round trips, type registry,
  services against a mocked HealthDataStore, Robolectric for writes)
- library/api/library.api: public API dump
- samsung-health-data-stub/: documented-API stand-in for the SDK AAR
- app/: Jetpack Compose MVVM demo with a row per public library call
- Gradle 8.14, AGP 8.13.2, Kotlin 2.2.21, Kotlin DSL, version catalog,
  ktlint, detekt, Kover, binary-compatibility-validator; drop jcenter/Bintray
- .github/workflows: CI and release-please; jitpack.yml
- AGENTS.md (+ CLAUDE.md symlink), README, CONTRIBUTING, PR template,
  docs/adr 0001-0003
- remove the 0.0.x sources, the 1.4.0 SDK jar and tracked .idea files

Tests: 67 unit tests green against the real Samsung Health Data SDK 1.1.0
and against the stub; line coverage 98.3% (koverVerify minBound 98); ktlint,
detekt, Android lint and apiCheck clean; library and Example app build.

BREAKING CHANGE: 0.0.x API (resolvers, SessionType/DiscreteType, listener
interfaces, Gson json) is replaced. Add the Samsung Health Data SDK AAR to
your app, create SamsungHealthReporter(context), request permissions with
manager.requestPermissions and read/write through reader/writer; see the
README migration table.
…request

On a Pixel 7a with Samsung Health 7.00.6 in developer mode, every read
permission is granted, while every write permission is rejected with SDK
error 2003 (ERR_ACCESS_CONTROL, "Permission is not allowed due to SDK
policy") until the partnership access code is entered. Requesting all
permissions at once therefore fails as a whole; the demo now requests reads
separately and can request each permission alone to list what the current
setup allows.

Changes:
- app/src/main/kotlin/com/kvs/samsunghealthreporter/example/service/ManagerDemos.kt:
  "Request every read permission" and "Request each permission alone" rows
- README.md: developer mode, access code and error 2003 explained
- .gitignore: ignore .idea/ IDE state

Tests: ktlint and detekt clean, 67 library unit tests green, Example app
builds; verified on a Pixel 7a: 25 of 25 reads granted, 11 of 11 writes
rejected with 2003; localDevice, device(id) and userProfile return real data.
The base64-encoded AAR (669 KB) exceeds GitHub's 48 KB secret limit, and
Samsung doesn't allow redistributing the SDK, so it can't live in this
public repository. CI now clones it from the private kvs-coder/samsung-health-sdk
repository with a read-only deploy key; without the key (fork PRs) the
build keeps using the SDK stub.

Changes:
- .github/workflows/ci.yml: clone the AAR with SAMSUNG_HEALTH_SDK_DEPLOY_KEY
  instead of decoding SAMSUNG_HEALTH_DATA_AAR_BASE64
- docs/adr/0003-sdk-aar-compile-only-with-stub.md: document the private repository

Tests: workflow YAML parses; the deploy key is registered read-only on
kvs-coder/samsung-health-sdk and the secret is set; the clone step runs on
the next CI run.
The directory only holds the git-ignored AAR, so a fresh checkout doesn't
have it and the copy failed after a successful clone.

Changes:
- .github/workflows/ci.yml: mkdir -p library/libs before the copy

Tests: PR #3 CI cloned the private repository with the deploy key; the
copy is the only failing command.
kvs-coder added a commit that referenced this pull request Oct 9, 2026
The directory only holds the git-ignored AAR, so a fresh checkout doesn't
have it and the copy failed after a successful clone.

Changes:
- .github/workflows/ci.yml: mkdir -p library/libs before the copy

Tests: PR #3 CI cloned the private repository with the deploy key; the
copy is the only failing command.
Adds arc42 documentation derived from the code, CI and the Pixel 7a run,
with Mermaid diagrams that GitHub renders inline: context, building blocks
(facade, services, types, payloads, decorators, SDK stub, Example app),
runtime flows (authorize, read, aggregate, write, observe), deployment
(JitPack, consumer apps, CI with the private SDK repository), crosscutting
concepts, ADR index, quality scenarios, risks and debt, and a glossary.

Changes:
- docs/arc42/README.md, 01-12: the twelve chapters
- README.md: link the architecture documentation
- AGENTS.md: list docs/arc42 in the directory structure, keep it current

Tests: all seven Mermaid diagrams render with @mermaid-js/mermaid-cli 11.4.2;
documentation only, no code change.
SamsungHealthObserver.observe returns a Flow, but kotlinx-coroutines-android
was an implementation dependency, published with runtime scope, so apps
couldn't compile calls to observe(). A probe module depending only on the
published library found it, and JitPack's POM for 18b2246 confirms the
runtime scope.

Changes:
- library/build.gradle.kts: kotlinx-coroutines-android as api

Tests: the published POM lists kotlinx-coroutines-android with compile scope;
a consumer module without the Samsung SDK now compiles read, aggregate,
insert, requestPermissions and observe calls; 67 unit tests, apiCheck and
ktlint green.
Local task notes (ISSUE-*.md at the repo root) are for local use only: they
are git-ignored and never referenced from committed files.

Changes:
- .gitignore: ignore ISSUE-*.md
- AGENTS.md: local issues are git-ignored and never committed
- docs/arc42/11-risks-and-technical-debt.md: drop the local-notes debt item

Tests: repository hygiene only; git check-ignore confirms the files are
ignored.
@kvs-coder
kvs-coder force-pushed the vk/health-data-sdk-migration branch from 4e0112e to a912f7a Compare October 9, 2026 15:37
Nothing threw NotAvailable: availability is SamsungHealthReporter.isAvailable
and setup problems arrive as Resolvable. Removing it before 1.0.0 keeps
consumers from writing catch branches that can't run. Also removes the
unused internal TimeRange.asInstantTimeFilter.

Changes:
- library/src/main/kotlin/com/kvs/samsunghealthreporter/SamsungHealthException.kt: drop NotAvailable
- library/src/main/kotlin/com/kvs/samsunghealthreporter/decorator/Extensions+TimeRange.kt: drop asInstantTimeFilter
- library/api/library.api: regenerated
- README.md, docs/arc42/05, docs/arc42/11: drop NotAvailable

Tests: 97 unit tests green against the real SDK and the stub; apiCheck passes.

BREAKING CHANGE: SamsungHealthException.NotAvailable no longer exists; check
SamsungHealthReporter.isAvailable and handle SamsungHealthException.Resolvable.
97 tests (was 67). Line coverage 99.94%, branch coverage 74.5%: of the 448
missed branches, 447 are kotlinx.serialization-generated (write$Self and
decoding constructors) and unreachable because payloads always encode
defaults. Kover now gates both units.

The tests against the real SDK showed that DeviceType is a sealed interface
(only DeviceGroup and AccessoryType), that Permission is a final class
without copy(), and that heart-rate points need an end time; the device
mapping and the stub follow.

Changes:
- library/src/test/kotlin/.../decorator/DecoratorTest.kt: map conversion,
  error wrapping, devices, enums, aggregates, data point helpers, filters
- library/src/test/kotlin/.../payload/PayloadContractTest.kt: every factory,
  optional fields, SDK-side nulls, skin temperature series, user profile
- library/src/test/kotlin/.../service/ServiceEdgeCaseTest.kt: paging under the
  limit, user profile, date grouping, skipped changes, client ids for every
  writable type, resolve, default permissions, facade connection, exceptions
- library/src/test/kotlin/.../{ReadOnlySampleTest,ValueTypeTest,Fixtures}.kt: extended
- library/build.gradle.kts: Kover gates minBound(99, LINE), minBound(74, BRANCH)
- library/src/main/kotlin/.../decorator/Extensions+Device.kt: exhaustive when over the sealed DeviceType
- library/src/main/kotlin/.../service/SamsungHealthWriter.kt: simpler client id assignment
- samsung-health-data-stub: sealed DeviceType; Permission as a final class like the SDK
- AGENTS.md, docs/arc42/01, 08, 10: coverage gates and test counts

Tests: 97 tests, 0 failures against the real SDK and the stub; koverVerify,
ktlint, detekt, Android lint and apiCheck pass.
kvs-coder added a commit that referenced this pull request Oct 9, 2026
GitHub forces Node.js 20 actions onto Node.js 24 and flags them as
deprecated on every run.

Changes:
- .github/workflows/ci.yml: actions/checkout@v7, actions/setup-java@v6,
  gradle/actions/setup-gradle@v6, actions/upload-artifact@v7
- .github/workflows/release.yml: actions/checkout-free release-please-action@v5
  (only breaking change: Node.js 24; inputs unchanged)

Tests: both workflows parse; CI on PR #3 runs with the new versions.
GitHub forces Node.js 20 actions onto Node.js 24 and flags them as
deprecated on every run.

Changes:
- .github/workflows/ci.yml: actions/checkout@v7, actions/setup-java@v6,
  gradle/actions/setup-gradle@v6, actions/upload-artifact@v7
- .github/workflows/release.yml: googleapis/release-please-action@v5
  (its only breaking change is Node.js 24; inputs unchanged)

Tests: both workflows parse; CI on PR #3 runs with the new versions.
@kvs-coder
kvs-coder force-pushed the vk/health-data-sdk-migration branch from ad16fe1 to ed3d58d Compare October 9, 2026 16:31
CI warned that Gradle 8.14 is out of date and that ubuntu-latest moves to
Ubuntu 26.04 from 19.10.2026. Gradle 9.6+ needs AGP 9, whose built-in Kotlin
removes the kotlin-android plugin the binary-compatibility validator hooks
into, and Kotlin 2.4.21's own ABI validation dumps nothing for such Android
libraries; opting out of built-in Kotlin needs two deprecated AGP flags. So
this takes Gradle 9.5.1, the newest Gradle AGP 8.13 runs on, and records AGP 9
as debt.

Changes:
- gradle/wrapper, gradlew, gradlew.bat: Gradle 9.5.1
- gradle/libs.versions.toml: Kotlin 2.4.21, Kover 0.9.11, ktlint plugin 14.2.0,
  binary-compatibility-validator 0.18.2
- .github/workflows/ci.yml, release.yml: runs-on ubuntu-26.04
- docs/arc42/02, 11: toolchain constraint and AGP 9 debt

Tests: 97 unit tests green against the real SDK and the stub; ktlint,
detekt, Android lint, koverVerify, apiCheck, library and Example app builds
pass on Gradle 9.5.1.
Changes:
- README.md: menu path to developer mode, the read toggle, and where the
  partnership access code goes for writes

Tests: documentation only.
@kvs-coder
kvs-coder merged commit b3b601f into master Oct 9, 2026
2 checks passed
@kvs-coder
kvs-coder deleted the vk/health-data-sdk-migration branch October 9, 2026 17:15
@github-actions github-actions Bot mentioned this pull request Oct 9, 2026
kvs-coder added a commit that referenced this pull request Oct 9, 2026
…DK (#3)

## Summary
Rebuilds the library on the Samsung Health Data SDK 1.1.0 (the old
Samsung Health SDK for Android was deprecated on 31.07.2025) with the
HealthKitReporter architecture: one `SamsungHealthReporter` with a
reader, writer, observer and manager, library-owned types and
`@Serializable` payloads, suspend API, no SDK types in the public API.
Breaking: releases as 1.0.0.

## Changes
- `library/`: facade, services, 25 `HealthType`s, 20 `Aggregation`s, 15
sample payloads + `UserProfile`, 67 unit tests, `api/library.api`
- `samsung-health-data-stub/`: never-published stand-in for the
login-gated, non-redistributable SDK AAR
- `app/`: Jetpack Compose demo with a row per public call, plus
permission diagnostics
- Build: Gradle 8.14, AGP 8.13.2, Kotlin 2.2.21, ktlint, detekt, Kover,
binary-compatibility-validator; CI + release-please; CI fetches the real
AAR from the private `kvs-coder/samsung-health-sdk` repo with a
read-only deploy key
- Docs: `AGENTS.md` (+ `CLAUDE.md`), README with migration table,
CONTRIBUTING, ADRs 0001–0003, `ISSUE-*.md`
- Removed the 0.0.x sources, the 1.4.0 SDK jar and tracked `.idea/`

## Tests
- Unit tests: 67 executed, 0 failed, against the real SDK AAR and the
stub; coverage 98.3% (Kover gate 98)
- ktlint / detekt / Android lint: clean
- apiCheck: passes, `library.api` committed
- Example app build: passes; on a Pixel 7a (Samsung Health 7.00.6,
developer mode) all 25 read permissions are granted and device/profile
reads return real data; writes fail with SDK error 2003 until Samsung's
partnership access code is entered
kvs-coder pushed a commit that referenced this pull request Oct 9, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.0.0](0.0.6...1.0.0)
(2026-10-09)


### ⚠ BREAKING CHANGES

* rebuild SamsungHealthReporter on the Samsung Health Data SDK
([#3](#3))

### Code Refactoring

* rebuild SamsungHealthReporter on the Samsung Health Data SDK
([#3](#3))
([1f862e6](1f862e6))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant