Repository navigation
Conversation
Pull the osmdroid set-up out of OSMMapFragment, so that other screens showing an osmdroid map can share it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Expose the waypoints whose regions were last entered, keyed by tst as exported waypoints are, so that other features can react to being in a region. It's updated atomically from each changed waypoint, including the unnotified updates that transitions make. The in-memory test repo now implements update and delete. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add a flow of the connected Wi-Fi network's SSID. It follows Wi-Fi itself rather than the default network, so it's still known behind a VPN, treats a redacted SSID as unknown, and only watches Wi-Fi while it's collected. Also list the SSIDs from the latest Wi-Fi scan, strongest first. Requesting a fresh scan needs CHANGE_WIFI_STATE. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Context profiles change the locator settings automatically depending on the device's context, replacing the automation apps (e.g. Tasker) that people use to switch monitoring modes. They're off by default, and nothing about the device is watched until they're turned on. A profile has conditions (a Wi-Fi network, any Wi-Fi, a Bluetooth device, charging, charging from a cable, wireless or dock, being inside a waypoint's region) and applies when any, all or none of them match. Profiles are kept in priority order and the first that applies wins. Its overrides (monitoring mode, intervals, displacement, priority, ping) replace the matching preferences while it applies, and a static location can be reported instead of tracking at all. ContextProfileManager matches the profiles against the DeviceContext and publishes the resulting LocatorSettings, which the location request, ping schedule, publish suppression, significant motion rate limit and displayed monitoring mode now use instead of the raw preferences. Nothing is matched, requested or pinged until every part of the device context has reported once, so that a profile isn't applied for an empty context at startup. Choosing a monitoring mode by hand, or changing a preference the applied profile overrides, suspends that profile until a different one applies, and that's remembered across restarts. While a static location is reported, real locations are only sent when the user explicitly asks for one, and it isn't used to detect region transitions. Profiles are stored as JSON in the exportable contextProfiles preference, documented in PREFERENCES.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add a Context profiles screen to turn profiles on, see which profile applies right now (or that one is paused by a manual change), and list, add and reorder the profiles. Each profile is edited on its own screen: its conditions and how they match, and its overrides, showing only the ones that make a difference in the chosen monitoring mode. Wi-Fi networks can be picked from the nearby ones, several at once, and Bluetooth devices from the paired ones, asking for BLUETOOTH_CONNECT only then. A static location is picked on a map, with the coordinates shown and editable underneath and a button to go to the current location. The picker uses OpenStreetMap so that it works the same in both flavours. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The location picker always showed OpenStreetMap, so it could look different from the main map. It now shows the same kind of map the user has chosen for the main map: Google Maps, in the chosen map type and with the same night style, or OpenStreetMap with the chosen tiles, inverted at night as on the main map. The picker talks to a small PickerMap interface, with an OpenStreetMap implementation shared by both flavours and a Google Maps one in gms, picked per flavour like the main map fragment. The dark mode tile handling is shared with the main OpenStreetMap map. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ContextProfileManager saved the suspended profile while holding its own lock. Saving a preference notifies listeners while holding the preferences' listener lock, and the manager's onPreferenceChanged is called with that held and then takes the manager's lock, so a device context change and a preference change at the same time could deadlock. Save it after releasing the lock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Region transitions were published with the real location that triggered them, even while a static location was being reported. They're now reported at the static location. Real locations requested before it's known which profile applies (e.g. by significant motion or a remote reportLocation at startup) could be published, though that profile might report a static location. They're now only published once it's known, unless the user asked for their location. A static location also went through the inaccurate location filter, so with that set to its accuracy or lower, nothing was published at all. Its accuracy is configured rather than measured, so it no longer does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Bluetooth connection broadcasts are sent by the Bluetooth stack rather than the system, and before T a receiver registered as not exported requires a permission of ours, which it doesn't have, so they were never received there. Register the receiver as exported; they're protected broadcasts, so other apps can't send them. Also fixes lint warnings: helpers used from nested classes are internal rather than private to avoid synthetic accessors, and the Bluetooth permission request drops an SDK check that's always true. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One profile that couldn't be decoded, e.g. one using a condition from a newer version, made decoding fail for them all, and saving the list afterwards then lost every profile. Decode each profile on its own, leaving out any that can't be decoded, and keep those when saving the others. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Losing any Wi-Fi network reported that there was no Wi-Fi, even if another was still connected, as can briefly happen while switching networks. Keep track of each connected Wi-Fi network's SSID instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
orFallbackAfter checked whether anything had been emitted separately from sending, so the fallback could win the check but be sent after a real value that arrived at the same moment, leaving that part of the device context stale. Check and send together under a mutex. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A momentary change in the device context, e.g. Wi-Fi or a charger dropping out for a second, switched profiles straight away, and dropped the suspension of a profile the user had overridden by hand, so their choice was silently undone when it came back. Once the context is known, a change now has to last ten seconds before profiles are matched again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add the contextProfiles and contextProfilesEnabled preferences to the preference getter, setter and export tests, as with the other preferences, and check that the suspended profile isn't exported. Also test that profiles survive importing and exporting a configuration, including region conditions keeping their waypoint, and that malformed profiles import as none. Also adds labels for the new preferences to the configuration import screen, rather than it showing their raw keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move the DeviceContextProvider binding into its own DeviceContextModule, like GeofencingCapabilityModule, so that instrumented tests can replace it with a FakeDeviceContextProvider whose Wi-Fi, Bluetooth and charging they set, as an emulator's can't be. Adds end to end tests that a profile's static location is published instead of real locations, that an applied profile's monitoring mode shows on the map and in the notification, and that a change monitoring intent suspends it; tests of adding, configuring, deleting and reordering profiles and showing the one that applies; and tests of the location picker's results. Also documents that context changes have to settle before profiles switch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rasbandit
marked this pull request as ready for review
October 8, 2026 08:22
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds context profiles: the locator settings change automatically depending on what the device is connected to or doing. The main use is saving battery while still reporting accurately. Today people do this with Tasker sending
CHANGE_MONITORINGintents; this makes it native.Examples it handles:
It's off by default. While it's off, nothing about the device is watched and behaviour is unchanged.
What's in it
locatorInterval,moveModeLocatorInterval,locatorDisplacement,locatorPriority,ping, and an optional static location that's reported instead of tracking.CHANGE_MONITORINGintent), or changing a preference the applied profile overrides, suspends that profile until a different one applies. This survives restarts.Design
ContextProfileManager. It matches profiles against aDeviceContext(Wi-Fi, Bluetooth, charging, entered regions) and publishes the resultingLocatorSettings. The location request, ping schedule, publish suppression, significant-motion rate limit and displayed monitoring mode read those settings instead of the raw preferences.USER). Other on-demand requests (e.g. remotereportLocation) get the static location, and it's not used for region transition detection.tst, like exported waypoints do, so they survive waypoint re-imports.Open questions for maintainers
contextProfilespreference, becausePreferencesStoreonly handles primitives. That means escaped JSON in.otrcexports. Would you prefer a typed preference with a serializer, or something else? I'm happy to rework it.BLUETOOTH(maxSdk 30) andBLUETOOTH_CONNECTare added for Bluetooth conditions. The runtime permission is only requested when a Bluetooth condition is added.CHANGE_WIFI_STATEis only for requesting a fresh scan in the Wi-Fi picker. Without it the picker falls back to cached scan results, which are often empty. It can be dropped if you'd rather.osslimitation. Without OS geofencing, region transitions come from location fixes, so a profile that combines a region condition with a static location can't detect leaving the region. This is documented rather than solved.Testing
PreferencesGettersAndSetters,PreferenceTest,ImportExportTestandLoadViewModelTestas with other preferencesContextProfilesPreferencesTests: add, configure, delete and reorder profiles, and show the active oneContextProfileTests: static location published instead of real fixes, the profile's mode on the map and in the notification,CHANGE_MONITORINGsuspending a profileLocationPickerActivityTests: the picker's resultsFakeDeviceContextProviderswapped in through@TestInstallIn, the same way asTestGeofencingCapabilityModule, because an emulator's Wi-Fi, Bluetooth and charging state can't be set.ktfmtCheckassembleDebug assembleAndroidTest assembleReleasecreateGmsDebugUnitTestCoverageReport, all passinglint: nothing new from this branch apart from the untranslated new stringsContextProfilesPreferencesTests(passing on an API 36 emulator).ContextProfileTestsandLocationPickerActivityTestshaven't been run locally (the only emulator available was busy with another project), so CI will be their first run.AI assistance
This was written with Claude Code, with me directing the design, reviewing it and testing on my own device. The commits carry a
Co-Authored-Bytrailer.🤖 Generated with Claude Code