Skip to content

Forbid usage of Build.Version.SDK_INT in favor of sdkVersion#6874

Open
TimoPtr wants to merge 3 commits into
mainfrom
feature/sdk_version
Open

Forbid usage of Build.Version.SDK_INT in favor of sdkVersion#6874
TimoPtr wants to merge 3 commits into
mainfrom
feature/sdk_version

Conversation

@TimoPtr
Copy link
Copy Markdown
Member

@TimoPtr TimoPtr commented May 21, 2026

Summary

Using Build.Version.SDK_INT makes testing some branches impossible because of that we used to do some ugly constructor that has the sdkInt has parameter. I found out the existence of https://developer.android.com/reference/androidx/annotation/ChecksSdkIntAtLeast that allow a method to tell the linter that it properly test this specific version. I've created a static field named sdkVersion that helps replace all the usage of the SDK_INT and a lint rule to forbid the usage of SDK_INT directly.

I used the same pattern as the one we have in HomeAssistantVersion with atLeast. We cannot override the compareTo operator but I think it is more explicit in the end to use atLeast. We also connot make it infix the annotation doesn't support it.

This PR is split in multiple commits to ease the review, the first commit is the actual logic, the second is the replace of all the usage.

Checklist

  • New or updated tests have been added to cover the changes following the testing guidelines.
  • The code follows the project's code style and best_practices.
  • The changes have been thoroughly tested, and edge cases have been considered.
  • Changes are backward compatible whenever feasible. Any breaking changes are documented in the changelog for users and/or in the code for developers depending on the relevance.

Any other notes

I did not create a rule for test to reset the version since it was already something we had to handle manually but we might reconsider later.

@TimoPtr TimoPtr marked this pull request as ready for review May 21, 2026 09:11
Copilot AI review requested due to automatic review settings May 21, 2026 09:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a test-friendly sdkVersion provider (with isAtLeast(api) gates recognized by Android Lint) and adds a custom lint rule to forbid direct reads of Build.VERSION.SDK_INT, then migrates the codebase to use the new provider for SDK version checks.

Changes:

  • Added SdkVersionProvider + global sdkVersion override point for tests, and replaced most Build.VERSION.SDK_INT checks with sdkVersion.isAtLeast(...)
  • Added a lint check (SdkVersionAccess) (with unit tests) to prevent new direct SDK_INT usage
  • Updated permission/version-dependent code paths across app/common/wear (and adjusted affected tests)

Reviewed changes

Copilot reviewed 96 out of 96 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
wear/src/main/kotlin/io/homeassistant/companion/android/tiles/TileViews.kt Switch haptic gating from SDK_INT to sdkVersion
wear/src/main/kotlin/io/homeassistant/companion/android/sensors/HeartRateSensorManager.kt Use sdkVersion for permission gating
wear/src/main/kotlin/io/homeassistant/companion/android/sensors/HealthServicesSensorManager.kt Use sdkVersion for API-availability flag
wear/src/main/kotlin/io/homeassistant/companion/android/sensors/BedtimeModeSensorManager.kt Use sdkVersion for sensor availability
wear/src/main/kotlin/io/homeassistant/companion/android/HomeAssistantApplication.kt Replace SDK checks and log SDK via sdkVersion
wear/src/main/kotlin/io/homeassistant/companion/android/home/views/SensorUi.kt Use sdkVersion for permission UI logic
wear/src/main/kotlin/io/homeassistant/companion/android/home/HomeActivity.kt Use sdkVersion for notification permission gating
lint/src/test/kotlin/io/homeassistant/lint/sdkversion/SdkVersionDetectorTest.kt Add tests for new lint detector and suppression behavior
lint/src/main/kotlin/io/homeassistant/lint/sdkversion/SdkVersionDetector.kt New lint detector forbidding Build.VERSION.SDK_INT reads
lint/src/main/kotlin/io/homeassistant/lint/LintRegistry.kt Register SdkVersionAccess issue
common/src/main/kotlin/io/homeassistant/companion/android/di/DataModule.kt Provide OS version string via sdkVersion.toString()
common/src/main/kotlin/io/homeassistant/companion/android/database/migration/Utils.kt Use sdkVersion for notification channel creation gating
common/src/main/kotlin/io/homeassistant/companion/android/common/util/SdkVersionProvider.kt New provider + global sdkVersion with test-only setter
common/src/main/kotlin/io/homeassistant/companion/android/common/util/NotificationManagerExtensions.kt Use sdkVersion for N+ active-notification APIs
common/src/main/kotlin/io/homeassistant/companion/android/common/util/ExoPlayerExt.kt Gate HttpEngine usage via sdkVersion
common/src/main/kotlin/io/homeassistant/companion/android/common/util/DisabledLocationHandler.kt Replace SDK checks with sdkVersion
common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/StepsSensorManager.kt Use sdkVersion for permission requirements
common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/SensorWorkerBase.kt Use sdkVersion for foreground service type + channel gating
common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/SensorReceiverBase.kt Use sdkVersion for notification channel gating
common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/SensorManager.kt Use sdkVersion for PackageManager/AppOps API branching
common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/PhoneStateSensorManager.kt Use sdkVersion for feature branching
common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/NetworkSensorManager.kt Replace multiple SDK gates with sdkVersion
common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/MobileDataManager.kt Use sdkVersion for permission + telephony API branching
common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/BluetoothSensorManager.kt Use sdkVersion for Bluetooth permission branching
common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/BatterySensorManager.kt Replace SDK gates with sdkVersion
common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/AudioSensorManager.kt Use sdkVersion for update type + sensor availability
common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/AppSensorManagerBase.kt Use sdkVersion for API-dependent sensors
common/src/main/kotlin/io/homeassistant/companion/android/common/notifications/NotificationFunctions.kt Use sdkVersion for notification channel and settings gating
common/src/main/kotlin/io/homeassistant/companion/android/common/notifications/NotificationDeleteReceiver.kt Use sdkVersion for getSerializableExtra overload branching
common/src/main/kotlin/io/homeassistant/companion/android/common/data/network/WifiHelperImpl.kt Use sdkVersion for UNKNOWN_SSID behavior branching
common/src/main/kotlin/io/homeassistant/companion/android/common/data/integration/Entity.kt Use sdkVersion for time parsing capability gating
common/src/main/kotlin/io/homeassistant/companion/android/common/compose/util/PainterResourceUtil.kt Use sdkVersion for adaptive icon support gating
common/src/main/kotlin/io/homeassistant/companion/android/common/bluetooth/ble/MonitoringManager.kt Use sdkVersion for channel creation gating
app/src/test/kotlin/io/homeassistant/companion/android/frontend/permissions/PermissionManagerTest.kt Switch tests to override global sdkVersion instead of ctor param
app/src/minimal/kotlin/io/homeassistant/companion/android/location/LocationProvider.kt Use sdkVersion for provider selection
app/src/main/kotlin/io/homeassistant/companion/android/widgets/todo/TodoWidgetState.kt Use sdkVersion for dynamic color background gating
app/src/main/kotlin/io/homeassistant/companion/android/widgets/todo/TodoWidgetConfigureActivity.kt Use sdkVersion for pin-widget gating
app/src/main/kotlin/io/homeassistant/companion/android/widgets/template/TemplateWidgetConfigureActivity.kt Use sdkVersion for pin-widget gating
app/src/main/kotlin/io/homeassistant/companion/android/widgets/mediaplayer/MediaPlayerControlsWidgetConfigureActivity.kt Use sdkVersion for pin-widget gating
app/src/main/kotlin/io/homeassistant/companion/android/widgets/entity/EntityWidgetConfigureActivity.kt Use sdkVersion for pin-widget gating
app/src/main/kotlin/io/homeassistant/companion/android/widgets/camera/CameraWidgetConfigureActivity.kt Use sdkVersion for pin-widget gating
app/src/main/kotlin/io/homeassistant/companion/android/widgets/button/ButtonWidgetConfigureActivity.kt Use sdkVersion for pin-widget gating
app/src/main/kotlin/io/homeassistant/companion/android/webview/WebViewContentScreen.kt Default notification-permission support via sdkVersion
app/src/main/kotlin/io/homeassistant/companion/android/webview/WebViewActivity.kt Replace SDK gates (lockscreen, download, WebView pkg, LAN perm, PiP)
app/src/main/kotlin/io/homeassistant/companion/android/websocket/WebsocketManager.kt Use sdkVersion for channels/foreground service type gating
app/src/main/kotlin/io/homeassistant/companion/android/util/vehicle/SettingsAction.kt Use sdkVersion for Android 14 display security workaround
app/src/main/kotlin/io/homeassistant/companion/android/util/vehicle/NativeMode.kt Use sdkVersion for Android 14 display security workaround
app/src/main/kotlin/io/homeassistant/companion/android/util/DataUriDownloadManager.kt Use sdkVersion for scoped storage + channel creation gating
app/src/main/kotlin/io/homeassistant/companion/android/util/ContextExtensions.kt Use sdkVersion for connectivity API branching
app/src/main/kotlin/io/homeassistant/companion/android/util/compose/webview/HAWebView.kt Use sdkVersion for night mode implementation branching
app/src/main/kotlin/io/homeassistant/companion/android/util/compose/LocationPermissionState.kt Use sdkVersion for permission set composition
app/src/main/kotlin/io/homeassistant/companion/android/themes/NightModeManager.kt Use sdkVersion to choose default theme behavior
app/src/main/kotlin/io/homeassistant/companion/android/settings/widgets/ManageWidgetsViewModel.kt Use sdkVersion for pin-widget support detection
app/src/main/kotlin/io/homeassistant/companion/android/settings/websocket/views/WebsocketSettingView.kt Use sdkVersion for notification settings visibility gating
app/src/main/kotlin/io/homeassistant/companion/android/settings/ssid/views/SsidView.kt Use sdkVersion for UNKNOWN_SSID behavior branching
app/src/main/kotlin/io/homeassistant/companion/android/settings/ssid/SsidFragment.kt Use sdkVersion for location permission branching
app/src/main/kotlin/io/homeassistant/companion/android/settings/shortcuts/ManageShortcutsViewModel.kt Use sdkVersion for shortcut pinning gates
app/src/main/kotlin/io/homeassistant/companion/android/settings/SettingsPresenterImpl.kt Use sdkVersion for notification suggestion gating
app/src/main/kotlin/io/homeassistant/companion/android/settings/SettingsFragment.kt Replace many preference visibility SDK gates with sdkVersion
app/src/main/kotlin/io/homeassistant/companion/android/settings/sensor/views/SensorUpdateFrequencyView.kt Use sdkVersion for notification-channel info visibility
app/src/main/kotlin/io/homeassistant/companion/android/settings/sensor/SensorDetailViewModel.kt Use sdkVersion for PackageManager overload branching and permission flow
app/src/main/kotlin/io/homeassistant/companion/android/settings/sensor/SensorDetailFragment.kt Use sdkVersion for background-location request branching
app/src/main/kotlin/io/homeassistant/companion/android/settings/qs/views/ManageTilesView.kt Use sdkVersion for subtitle support gating
app/src/main/kotlin/io/homeassistant/companion/android/settings/qs/ManageTilesViewModel.kt Use sdkVersion for add-vs-save behavior and tile add flow
app/src/main/kotlin/io/homeassistant/companion/android/settings/log/LogFragment.kt Use sdkVersion for intent query overload branching
app/src/main/kotlin/io/homeassistant/companion/android/settings/language/LanguagesManager.kt Use sdkVersion for locale migration/application branching
app/src/main/kotlin/io/homeassistant/companion/android/settings/controls/views/ManageControlsView.kt Use sdkVersion for Controls Panel availability branching
app/src/main/kotlin/io/homeassistant/companion/android/settings/controls/ManageControlsViewModel.kt Use sdkVersion for Controls Panel enable/disable gating
app/src/main/kotlin/io/homeassistant/companion/android/settings/assist/DefaultAssistantManager.kt Use sdkVersion for RoleManager gate
app/src/main/kotlin/io/homeassistant/companion/android/sensors/NotificationSensorManager.kt Use sdkVersion for channelId exposure gating
app/src/main/kotlin/io/homeassistant/companion/android/sensors/LastAppSensorManager.kt Use sdkVersion for PackageManager overload branching
app/src/main/kotlin/io/homeassistant/companion/android/sensors/GeocodeSensorManager.kt Use sdkVersion for permission set + Geocoder overload branching
app/src/main/kotlin/io/homeassistant/companion/android/sensors/CarSensorManager.kt Use sdkVersion for API availability gating
app/src/main/kotlin/io/homeassistant/companion/android/qs/TilePreferenceActivity.kt Use sdkVersion for BundleCompat parcelable branching
app/src/main/kotlin/io/homeassistant/companion/android/qs/TileExtensions.kt Use sdkVersion for subtitle and vibration API branching
app/src/main/kotlin/io/homeassistant/companion/android/onboarding/serverdiscovery/ServerDiscoveryScreen.kt Use sdkVersion for local network permission requirement gating
app/src/main/kotlin/io/homeassistant/companion/android/onboarding/serverdiscovery/HomeAssistantSearcher.kt Use sdkVersion for NSD stopServiceResolution API gate
app/src/main/kotlin/io/homeassistant/companion/android/notifications/MessagingManager.kt Replace multiple SDK gates with sdkVersion (channels, groups, Bluetooth, live, etc.)
app/src/main/kotlin/io/homeassistant/companion/android/launch/LaunchActivity.kt Use sdkVersion for PiP gating
app/src/main/kotlin/io/homeassistant/companion/android/improv/ui/ImprovSheetView.kt Use sdkVersion for UNKNOWN_SSID behavior branching
app/src/main/kotlin/io/homeassistant/companion/android/improv/ImprovRepositoryImpl.kt Use sdkVersion for Bluetooth permission requirements
app/src/main/kotlin/io/homeassistant/companion/android/HomeAssistantApplication.kt Replace SDK checks and log SDK via sdkVersion
app/src/main/kotlin/io/homeassistant/companion/android/frontend/permissions/PermissionManager.kt Remove test-only sdkInt ctor param; gate with sdkVersion
app/src/main/kotlin/io/homeassistant/companion/android/frontend/haptic/HapticFeedbackPerformer.kt Use sdkVersion for haptic API branching
app/src/main/kotlin/io/homeassistant/companion/android/controls/HaControlsProviderService.kt Use sdkVersion for domain minimum API filtering and auth-required gate
app/src/main/kotlin/io/homeassistant/companion/android/controls/HaControl.kt Use sdkVersion for Control#setAuthRequired gate
app/src/main/kotlin/io/homeassistant/companion/android/assist/service/AssistVoiceInteractionService.kt Use sdkVersion for foreground-service and channel API gates
app/src/main/kotlin/io/homeassistant/companion/android/assist/service/AssistRecognitionService.kt Use sdkVersion for T+ behavior gating
app/src/main/kotlin/io/homeassistant/companion/android/assist/AssistActivity.kt Use sdkVersion for lockscreen behavior branching
app/src/full/kotlin/io/homeassistant/companion/android/thread/ThreadManagerImpl.kt Use sdkVersion for Thread support gating
app/src/full/kotlin/io/homeassistant/companion/android/sensors/LocationSensorManager.kt Use sdkVersion for accuracy fields + permission branching
app/src/full/kotlin/io/homeassistant/companion/android/sensors/AndroidAutoSensorManager.kt Use sdkVersion for availability gating
app/src/full/kotlin/io/homeassistant/companion/android/sensors/ActivitySensorManager.kt Use sdkVersion for ACTIVITY_RECOGNITION permission gating
app/src/full/kotlin/io/homeassistant/companion/android/matter/MatterManagerImpl.kt Use sdkVersion for commissioning support gating
app/src/full/kotlin/io/homeassistant/companion/android/location/HighAccuracyLocationService.kt Use sdkVersion for channel creation and service type gating
app/src/debug/kotlin/io/homeassistant/companion/android/developer/DemoExoPlayerActivity.kt Use sdkVersion for lifecycle behavior gating

Comment on lines +60 to +63
@AfterEach
fun tearDown() {
sdkVersion = SdkVersionProvider { false }
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my description, I don't know yet what to do there.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jpelgrom I could actually make it fail if the test code is reaching the Provider so it force us to handle the case wdyt?

Comment on lines +8 to +11
/**
* Reports whether the current Android SDK level is at least [api]. Tests can substitute a fake
* provider to simulate a SDK version.
*
Comment on lines +222 to +223
@SuppressLint("ObsoleteSdkInt") // Needed for app module (minSdk 21) but obsolete for automotive (minSdk 29)
private val areCarSensorApisAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
private val areCarSensorApisAvailable = sdkVersion.isAtLeast(Build.VERSION_CODES.O)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh nice it means we won't have the issue anymore with the Automotive. In any case I was even wondering about dropping this lint check because it was more annoying than useful, last time I dropped a first I went over all the Build.VERSION_CODES bellow the one set as minimal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants