Skip to content

Migrate location stack off deprecated GoogleApiClient to FusedLocationProviderClient#1569

Merged
aaronbrethorst merged 1 commit into
OneBusAway:mainfrom
bmander:modernization/fused-location-client
Jun 13, 2026
Merged

Migrate location stack off deprecated GoogleApiClient to FusedLocationProviderClient#1569
aaronbrethorst merged 1 commit into
OneBusAway:mainfrom
bmander:modernization/fused-location-client

Conversation

@bmander

@bmander bmander commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Removes the deprecated GoogleApiClient (deprecated 2017, removed in current play-services-location majors) from the location stack. All real location work already flowed through FusedLocationProviderClient, so this is mostly deletion (−509/+70 across 21 files):

  • LocationHelper requests fused updates directly instead of via the connect()/onConnected() dance; the GoogleApiAvailability guard is preserved so devices without Play Services still fall back to LocationManager. Deprecated LocationRequest.create() chain replaced with LocationRequest.Builder.
  • Application.getLastKnownLocation() and ReportActivity.start() drop their GoogleApiClient parameters; ~10 holder classes lose their mGoogleApiClient fields and connect/disconnect lifecycle boilerplate.
  • Three bugs fixed in passing: LocationHelper(Context, int) never initialized mLocationRequest (NavigationService's fused subscription requested updates with a null request); SurveyWebViewActivity crashed in onStop() on devices without Play Services (lateinit client never assigned); Task.getResult() was called after isComplete() instead of isSuccessful(), which crashes on a failed task (e.g. permission revoked).

Verified: obaGoogleDebug + obaMaplibreDebug compile; LocationUtilsTest passes on a Pixel 7 Pro; live smoke test confirmed fused registration with HIGH_ACCURACY while foregrounded and clean teardown (zero leaked registrations) on backgrounding via dumpsys location.

Closes #1570

Summary by CodeRabbit

  • Refactor
    • Simplified and modernized location handling across the app by centralizing retrieval through a single API and removing legacy Play Services client usage
    • Location-dependent flows (reports, search, maps, trip planning, surveys, region selection, stop proximity) continue to work with the same user-facing behavior
    • Reduced lifecycle overhead for location services, improving stability and maintainability

@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Removes GoogleApiClient usage and lifecycle plumbing, refactors Application to a context-only getLastKnownLocation using FusedLocationProviderClient, updates LocationHelper to request fused updates via LocationCallback, and migrates all fragments, activities, controllers, tasks, and tests to the new API.

Changes

GoogleApiClient removal and location API modernization

Layer / File(s) Summary
Core Application & LocationUtils
onebusaway-android/src/main/java/org/onebusaway/android/app/Application.java, onebusaway-android/src/main/java/org/onebusaway/android/util/LocationUtils.java
Application.getLastKnownLocation(Context) is now the single public entry; getLocation2(Context) uses FusedLocationProviderClient and selects the newer of fused vs. API v1 locations; LocationUtils removes GoogleApiClient helper and nested callback.
LocationHelper fused update runtime
onebusaway-android/src/main/java/org/onebusaway/android/util/LocationHelper.java
Drops GoogleApiClient interfaces/state, builds LocationRequest via LocationRequest.Builder, requests/removes fused updates with requestLocationUpdates(..., mLocationCallback, null), and reads last-known-location via Application.
Map controllers & region task
onebusaway-android/src/main/java/org/onebusaway/android/map/BaseMapController.java, onebusaway-android/src/main/java/org/onebusaway/android/map/StopMapController.java, onebusaway-android/src/main/java/org/onebusaway/android/region/ObaRegionsTask.java
Removes GoogleApiClient fields/setup/teardown and switches auto-region and map flows to use Application.getLastKnownLocation(context).
Map fragments
onebusaway-android/src/google/.../BaseMapFragment.java, onebusaway-android/src/maplibre/.../MapLibreMapFragment.java
Updates onCreateView, setMyLocation, and onRegionTaskFinished to obtain last-known-location using Application.getLastKnownLocation(getActivity()) (no GoogleApiClient).
Reporting APIs & fragments
onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportActivity.java, .../ReportProblemFragmentBase.java, .../ReportStopProblemFragment.java, .../ReportTripProblemFragment.java
Removes GoogleApiClient parameters from ReportActivity.start/makeIntent, switches makeIntent and report fragments to the context-only last-known-location, and drops fragment client lifecycle wiring.
Home, search, regions, and lists UI
onebusaway-android/src/main/java/org/onebusaway/android/ui/HomeActivity.java, .../MySearchFragmentBase.java, .../SearchResultsFragment.java, .../RegionsFragment.java, .../ArrivalsListFragment.java
Removes GoogleApiClient imports/fields and onAttach/onStart/onStop lifecycle connection code; callsites now use Application.getLastKnownLocation(context); RegionsFragment adds FirebaseAnalytics.
Trip planning and survey UI
onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanActivity.java, .../TripPlanFragment.java, .../survey/SurveyWebViewActivity.kt
Removes legacy Google Play Services setup and updates feedback/report/address/survey location retrieval to the context-only API.
Instrumentation tests
onebusaway-android/src/androidTest/java/.../LocationUtilsTest.java
Removes GoogleApiClient import/field and @Before/@after setup/teardown; tests call Application.getLastKnownLocation(Context) overloads.

Sequence Diagram(s):

sequenceDiagram
  participant Caller as UI/Controller
  participant App as Application.getLastKnownLocation
  participant Fused as FusedLocationProviderClient
  participant LM as LocationManager
  Caller->>App: request last-known location (Context)
  App->>Fused: getLastLocation()
  Fused-->>App: fusedLocation (task.isSuccessful())
  App->>LM: requestLastKnownFromProviders()
  LM-->>App: api-v1 location
  App->>App: compare timestamps → return newer Location
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: migrating off GoogleApiClient to FusedLocationProviderClient, which is the primary objective of all the file changes.
Linked Issues check ✅ Passed The PR comprehensively addresses all objectives from issue #1570: eliminates GoogleApiClient scaffolding, replaces deprecated LocationRequest.create() with LocationRequest.Builder, removes ~10 Activities/Fragments mGoogleApiClient fields, and fixes LocationHelper(Context,int), SurveyWebViewActivity, and Task.isSuccessful() bugs.
Out of Scope Changes check ✅ Passed All changes are directly scoped to removing GoogleApiClient and migrating to FusedLocationProviderClient. Updates to LocationRequest initialization, GoogleApiAvailability checks, and removal of redundant lifecycle code are all core to the migration objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
onebusaway-android/src/androidTest/java/org/onebusaway/android/util/test/LocationUtilsTest.java (1)

172-178: ⚡ Quick win

Test comment no longer reflects actual behavior.

The comment claims this test runs "without Google Play Services" and "should be a Location API v1 location," but the new Application.getLastKnownLocation(Context) implementation tries Play Services first when available (see getLocation2 in Application.java). Since the test doesn't disable or mock Play Services, it may actually return a fused location rather than an API v1 location on devices with Play Services.

Consider updating the comment to reflect that this test retrieves a last-known location without explicitly requiring API v1, or add a check to skip/modify behavior when Play Services is available.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@onebusaway-android/src/androidTest/java/org/onebusaway/android/util/test/LocationUtilsTest.java`
around lines 172 - 178, The test comment for loc =
Application.getLastKnownLocation(getTargetContext()) is outdated because
Application.getLastKnownLocation(Context) now prefers Play Services (see
getLocation2) and may return a fused location; update the test to either (a)
change the comment to state it retrieves a last-known location that may come
from Play Services/fused provider rather than claiming "without Google Play
Services" and "Location API v1", or (b) add a runtime check to detect Play
Services availability and skip/adjust the assertion when Play Services is
present so the test no longer assumes an API v1 provider; reference
Application.getLastKnownLocation and getLocation2 when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@onebusaway-android/src/androidTest/java/org/onebusaway/android/util/test/LocationUtilsTest.java`:
- Around line 172-178: The test comment for loc =
Application.getLastKnownLocation(getTargetContext()) is outdated because
Application.getLastKnownLocation(Context) now prefers Play Services (see
getLocation2) and may return a fused location; update the test to either (a)
change the comment to state it retrieves a last-known location that may come
from Play Services/fused provider rather than claiming "without Google Play
Services" and "Location API v1", or (b) add a runtime check to detect Play
Services availability and skip/adjust the assertion when Play Services is
present so the test no longer assumes an API v1 provider; reference
Application.getLastKnownLocation and getLocation2 when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ed9a8308-2e2a-4080-b1d1-8282bbd74358

📥 Commits

Reviewing files that changed from the base of the PR and between 555cfd5 and 03218a5.

📒 Files selected for processing (21)
  • onebusaway-android/src/androidTest/java/org/onebusaway/android/util/test/LocationUtilsTest.java
  • onebusaway-android/src/google/java/org/onebusaway/android/map/googlemapsv2/BaseMapFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/app/Application.java
  • onebusaway-android/src/main/java/org/onebusaway/android/map/BaseMapController.java
  • onebusaway-android/src/main/java/org/onebusaway/android/map/StopMapController.java
  • onebusaway-android/src/main/java/org/onebusaway/android/region/ObaRegionsTask.java
  • onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportActivity.java
  • onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportProblemFragmentBase.java
  • onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportStopProblemFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportTripProblemFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/ArrivalsListFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/HomeActivity.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/MySearchFragmentBase.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/RegionsFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/SearchResultsFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanActivity.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/survey/activities/SurveyWebViewActivity.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/util/LocationHelper.java
  • onebusaway-android/src/main/java/org/onebusaway/android/util/LocationUtils.java
  • onebusaway-android/src/maplibre/java/org/onebusaway/android/map/maplibre/MapLibreMapFragment.java
💤 Files with no reviewable changes (3)
  • onebusaway-android/src/main/java/org/onebusaway/android/util/LocationUtils.java
  • onebusaway-android/src/main/java/org/onebusaway/android/map/BaseMapController.java
  • onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportProblemFragmentBase.java

…nProviderClient

GoogleApiClient was deprecated in 2017 and is removed in current
play-services-location majors, blocking Play Services upgrades. In this
codebase it was pure ceremony: all real location work already flowed
through FusedLocationProviderClient (which needs no connect/disconnect
lifecycle), so this change is mostly deletion:

- LocationHelper: drop the GoogleApiClient member, ConnectionCallbacks/
  OnConnectionFailedListener, and the connect()->onConnected() dance;
  request fused updates directly, gated only on Play Services
  availability (preserving the LocationManager fallback for devices
  without Play Services, e.g. the maplibre flavor). Replace the
  deprecated LocationRequest.create()/setPriority()/setInterval()/
  setFastestInterval() with LocationRequest.Builder + Priority.
- Application.getLastKnownLocation()/getLocation2(): drop the
  GoogleApiClient parameter; the GoogleApiAvailability check alone now
  gates the fused path. Delete the dead private getLocation() wrapper.
- LocationUtils: delete the getGoogleApiClientWithCallbacks() factory
  and LocationServicesCallback class.
- ReportActivity: drop the GoogleApiClient parameter from start() and
  makeIntent().
- Remove the mGoogleApiClient member and its connect/disconnect
  lifecycle boilerplate from 10 holder classes (HomeActivity, search/
  region/trip-plan/report fragments, map controllers, ObaRegionsTask,
  SurveyWebViewActivity) and update all getLastKnownLocation call sites.

Three bug fixes fall out of the migration:

- LocationHelper(Context, int) (used by NavigationService with a 1s
  interval) never initialized mLocationRequest, so its fused
  subscription requested updates with a null request. Both constructors
  now share one initialization path, and unregisterListener() now also
  tears down fused updates so the working subscription can't leak after
  navigation ends.
- SurveyWebViewActivity crashed in onStop() with
  UninitializedPropertyAccessException on devices without Play Services,
  because the lateinit client was only assigned when Play Services was
  present but disconnect() was called unconditionally.
- Application.getLocation2() called Task.getResult() after checking only
  task.isComplete() - a task that completed with a failure (e.g. a
  fast-failing getLastLocation() when location permission was revoked)
  would throw an uncaught RuntimeExecutionException. Now gated on
  task.isSuccessful(). Previously the isConnected() gate kept
  null-client callers out of this branch; with that gate gone, all
  callers reach it, so the check matters more.

Verified: obaGoogleDebug and obaMaplibreDebug variants and androidTest
sources compile; zero GoogleApiClient references remain in src/.
@bmander bmander force-pushed the modernization/fused-location-client branch from 03218a5 to b77e694 Compare June 7, 2026 01:10

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java (1)

661-661: ⚡ Quick win

Use consistent Context pattern for location retrieval.

Lines 661 and 692 use different Context-passing patterns: getActivity().getApplicationContext() vs getContext(). Since both calls retrieve location synchronously for immediate use, the application context vs activity context distinction is unnecessary.

Additionally, comparing with the pattern in ReportTripProblemFragment (context snippet 3) which uses getActivity(), there are now three different patterns across the migrated codebase.

For consistency and simplicity, consider using getContext() in both locations. This eliminates the NPE risk from chaining .getApplicationContext() and aligns with standard Fragment patterns where activity context is sufficient for synchronous operations.

♻️ Suggested unification
-        Location loc = Application.getLastKnownLocation(getActivity().getApplicationContext());
+        Location loc = Application.getLastKnownLocation(getContext());

This change makes both callsites use the same pattern and removes the intermediate getActivity() null-check requirement.

Also applies to: 692-692

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java`
at line 661, In TripPlanFragment replace the calls that pass
getActivity().getApplicationContext() into Application.getLastKnownLocation(...)
with getContext() (i.e., update the Location loc =
Application.getLastKnownLocation(...) call sites to use getContext()), doing the
same for the second occurrence; this unifies context usage with other fragments
and avoids chaining getActivity(), while keeping the synchronous location
retrieval intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java`:
- Line 661: In TripPlanFragment replace the calls that pass
getActivity().getApplicationContext() into Application.getLastKnownLocation(...)
with getContext() (i.e., update the Location loc =
Application.getLastKnownLocation(...) call sites to use getContext()), doing the
same for the second occurrence; this unifies context usage with other fragments
and avoids chaining getActivity(), while keeping the synchronous location
retrieval intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 990344e5-4126-4a2a-919b-538547ac8c08

📥 Commits

Reviewing files that changed from the base of the PR and between 03218a5 and b77e694.

📒 Files selected for processing (21)
  • onebusaway-android/src/androidTest/java/org/onebusaway/android/util/test/LocationUtilsTest.java
  • onebusaway-android/src/google/java/org/onebusaway/android/map/googlemapsv2/BaseMapFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/app/Application.java
  • onebusaway-android/src/main/java/org/onebusaway/android/map/BaseMapController.java
  • onebusaway-android/src/main/java/org/onebusaway/android/map/StopMapController.java
  • onebusaway-android/src/main/java/org/onebusaway/android/region/ObaRegionsTask.java
  • onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportActivity.java
  • onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportProblemFragmentBase.java
  • onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportStopProblemFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportTripProblemFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/ArrivalsListFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/HomeActivity.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/MySearchFragmentBase.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/RegionsFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/SearchResultsFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanActivity.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/survey/activities/SurveyWebViewActivity.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/util/LocationHelper.java
  • onebusaway-android/src/main/java/org/onebusaway/android/util/LocationUtils.java
  • onebusaway-android/src/maplibre/java/org/onebusaway/android/map/maplibre/MapLibreMapFragment.java
💤 Files with no reviewable changes (3)
  • onebusaway-android/src/main/java/org/onebusaway/android/util/LocationUtils.java
  • onebusaway-android/src/main/java/org/onebusaway/android/map/BaseMapController.java
  • onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportProblemFragmentBase.java
✅ Files skipped from review due to trivial changes (1)
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanActivity.java
🚧 Files skipped from review as they are similar to previous changes (14)
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/ArrivalsListFragment.java
  • onebusaway-android/src/maplibre/java/org/onebusaway/android/map/maplibre/MapLibreMapFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/map/StopMapController.java
  • onebusaway-android/src/google/java/org/onebusaway/android/map/googlemapsv2/BaseMapFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportTripProblemFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/region/ObaRegionsTask.java
  • onebusaway-android/src/main/java/org/onebusaway/android/report/ui/ReportActivity.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/MySearchFragmentBase.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/SearchResultsFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/HomeActivity.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/RegionsFragment.java
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/survey/activities/SurveyWebViewActivity.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/app/Application.java
  • onebusaway-android/src/main/java/org/onebusaway/android/util/LocationHelper.java

@aaronbrethorst aaronbrethorst left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice work, this looks like a great modernization. I love seeing more deleted LOC than added :)

@aaronbrethorst aaronbrethorst merged commit fe77336 into OneBusAway:main Jun 13, 2026
3 checks passed
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.

Location stack still built on deprecated GoogleApiClient, blocking play-services-location upgrades

2 participants