Skip to content

Conversation

@avazirna
Copy link
Contributor

@avazirna avazirna commented Aug 5, 2025

Product Description

Since the Kujaku library is no longer being actively maintained and the related feature have very low usage, we have decided to remove it from CommCare and retire all related features. This decision was also supported by issues observed during the Android 15 update, where accessing such features would cause CommCare to crash, it seems that Kujaku relies on native libraries that are not compatible with that version of Android.
With this removal, when users try to access features that rely on this feature they will see:

Feature Before After Notes
Capture location with MapBox SDK Changed to the `GeoPointMapActivity`
Capture a boundary capture_boundary_after No appropriate activity to resolve the intent
View on map from Case List view_on_map_from_case_list_before view_on_map_from_case_list_after Changed to `EntityMapActivity`
Show address from Case details No changes

Notes from reviewers:

  • There is code related to this that live in commcare-core that I'm reluctant to remove as it can causes issues to existing apps:
    • Model classes: Global and GeoOverlay;
    • Parsers: GlobalParser and GeoOverlayParser;

Tickets: https://dimagi.atlassian.net/browse/SAAS-18188, https://dimagi.atlassian.net/browse/SAAS-18042

Feature Flag

  • Appearance attribute maps
  • Custom property cc-use-mapbox-map

Safety Assurance

Safety story

Successfully tested locally.

QA Plan

This will undergo regression testing as always, but it will require the QA team to update the relevant test cases with the behavior described above.

Labels and Review

  • Do we need to enhance the manual QA test coverage ? If yes, the "QA Note" label is set correctly
  • Does the PR introduce any major changes worth communicating ? If yes, the "Release Note" label is set and a "Release Note" is specified in PR description.
  • Risk label is set correctly
  • The set of people pinged as reviewers is appropriate for the level of risk of the change

@coderabbitai
Copy link

coderabbitai bot commented Aug 5, 2025

📝 Walkthrough

Walkthrough

This change removes all Mapbox and Kujaku-based GIS and mapping features from the application. It deletes related activities (EntityMapboxActivity, DrawingBoundaryActivity, MapboxLocationPickerActivity), their layouts, supporting classes (such as AreaCalculator, MapEntity, and MapboxLocationPickerViewModel), and associated resources (styles, colors, and strings). The manifest and Gradle dependencies are updated to eliminate Mapbox/Kujaku components. Control flow in activities and widgets is simplified to always use the legacy map implementation, removing preference checks and feature toggles for Mapbox. All localization and UI resources specific to these features are also removed.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant App
    participant GeoPointMapActivity

    User->>App: Initiates map-based action (e.g., select location)
    App->>GeoPointMapActivity: Launches legacy map activity (always)
    GeoPointMapActivity->>User: Presents map UI for interaction
    User->>GeoPointMapActivity: Selects location/area
    GeoPointMapActivity->>App: Returns selected data
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~30-45 minutes

Possibly related PRs

  • Remove directly bundled libraries #2981: Updates dependencies by removing bundled libraries and adjusting Mapbox-related dependencies, which overlaps with this PR's removal of Mapbox/Kujaku dependencies and related code.

Suggested labels

skip-integration-tests

Suggested reviewers

  • shubham1g5

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch remove-kujaku

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
app/src/org/commcare/location/CommCareFusedLocationController.kt (1)

21-22: Parameter type and null check inconsistency.

The parameter type was changed to non-nullable LocationResult, but the null check result ?: return remains. If the API contract guarantees non-null results, the null check is redundant and should be removed. If null results are still possible, the parameter type should remain nullable.

 override fun onLocationResult(result: LocationResult) {
-    result ?: return
     mCurrentLocation = result.lastLocation
     mListener?.onLocationResult(mCurrentLocation!!)
 }

Or revert to nullable if the API still allows null:

-override fun onLocationResult(result: LocationResult) {
+override fun onLocationResult(result: LocationResult?) {
     result ?: return
     mCurrentLocation = result.lastLocation
     mListener?.onLocationResult(mCurrentLocation!!)
 }
app/build.gradle (1)

168-168: Consider removing unused Mapbox API key references.

Since the Mapbox library is being completely removed, the MAPBOX_SDK_API_KEY references in the build configuration may no longer be needed. Consider removing these to fully clean up Mapbox-related configuration.

-    MAPBOX_SDK_API_KEY = project.properties['MAPBOX_SDK_API_KEY'] ?: ''
-        buildConfigField 'String', 'MAPBOX_SDK_API_KEY', "\"${project.ext.MAPBOX_SDK_API_KEY}\""

Also applies to: 306-306

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 68a7d4a and e49746b.

📒 Files selected for processing (31)
  • app/AndroidManifest.xml (0 hunks)
  • app/assets/locales/android_translatable_strings.txt (0 hunks)
  • app/build.gradle (2 hunks)
  • app/res/color/button_colored_text.xml (0 hunks)
  • app/res/color/button_green_background.xml (0 hunks)
  • app/res/color/button_orange_background.xml (0 hunks)
  • app/res/color/button_red_background.xml (0 hunks)
  • app/res/layout/activity_drawing_boundary.xml (0 hunks)
  • app/res/layout/activity_entity_kujaku_map_info_view.xml (0 hunks)
  • app/res/layout/activity_entity_mapbox.xml (0 hunks)
  • app/res/layout/activity_mapbox_location_picker.xml (0 hunks)
  • app/res/values-es/strings.xml (0 hunks)
  • app/res/values-fr/strings.xml (0 hunks)
  • app/res/values-hi/strings.xml (0 hunks)
  • app/res/values-pt/strings.xml (0 hunks)
  • app/res/values-sw/strings.xml (0 hunks)
  • app/res/values-ti/strings.xml (0 hunks)
  • app/res/values/strings.xml (0 hunks)
  • app/res/values/styles.xml (0 hunks)
  • app/src/org/commcare/activities/EntitySelectActivity.java (1 hunks)
  • app/src/org/commcare/gis/AreaCalculator.kt (0 hunks)
  • app/src/org/commcare/gis/BaseMapboxActivity.kt (0 hunks)
  • app/src/org/commcare/gis/DrawingBoundaryActivity.kt (0 hunks)
  • app/src/org/commcare/gis/EntityMapUtils.kt (0 hunks)
  • app/src/org/commcare/gis/EntityMapboxActivity.kt (0 hunks)
  • app/src/org/commcare/gis/MapEntity.kt (0 hunks)
  • app/src/org/commcare/gis/MapboxLocationPickerActivity.kt (0 hunks)
  • app/src/org/commcare/gis/MapboxLocationPickerViewModel.kt (0 hunks)
  • app/src/org/commcare/location/CommCareFusedLocationController.kt (1 hunks)
  • app/src/org/commcare/preferences/HiddenPreferences.java (0 hunks)
  • app/src/org/commcare/views/widgets/GeoPointWidget.java (1 hunks)
💤 Files with no reviewable changes (27)
  • app/res/color/button_orange_background.xml
  • app/res/color/button_colored_text.xml
  • app/res/color/button_red_background.xml
  • app/res/color/button_green_background.xml
  • app/assets/locales/android_translatable_strings.txt
  • app/res/layout/activity_entity_kujaku_map_info_view.xml
  • app/res/layout/activity_entity_mapbox.xml
  • app/res/values-es/strings.xml
  • app/src/org/commcare/gis/MapEntity.kt
  • app/src/org/commcare/preferences/HiddenPreferences.java
  • app/res/layout/activity_mapbox_location_picker.xml
  • app/src/org/commcare/gis/AreaCalculator.kt
  • app/res/values/strings.xml
  • app/res/values-sw/strings.xml
  • app/src/org/commcare/gis/EntityMapboxActivity.kt
  • app/res/values-fr/strings.xml
  • app/res/layout/activity_drawing_boundary.xml
  • app/src/org/commcare/gis/EntityMapUtils.kt
  • app/res/values-hi/strings.xml
  • app/res/values-ti/strings.xml
  • app/res/values/styles.xml
  • app/res/values-pt/strings.xml
  • app/AndroidManifest.xml
  • app/src/org/commcare/gis/DrawingBoundaryActivity.kt
  • app/src/org/commcare/gis/MapboxLocationPickerActivity.kt
  • app/src/org/commcare/gis/BaseMapboxActivity.kt
  • app/src/org/commcare/gis/MapboxLocationPickerViewModel.kt
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: shubham1g5
PR: dimagi/commcare-android#2935
File: app/src/org/commcare/gis/EntityMapActivity.java:134-142
Timestamp: 2025-01-13T11:29:50.055Z
Learning: Google Maps SDK internally manages bitmap lifecycle for marker icons created through BitmapDescriptorFactory, so manual bitmap recycling is not needed in EntityMapActivity.java.
📚 Learning: google maps sdk internally manages bitmap lifecycle for marker icons created through bitmapdescripto...
Learnt from: shubham1g5
PR: dimagi/commcare-android#2935
File: app/src/org/commcare/gis/EntityMapActivity.java:134-142
Timestamp: 2025-01-13T11:29:50.055Z
Learning: Google Maps SDK internally manages bitmap lifecycle for marker icons created through BitmapDescriptorFactory, so manual bitmap recycling is not needed in EntityMapActivity.java.

Applied to files:

  • app/src/org/commcare/activities/EntitySelectActivity.java
  • app/src/org/commcare/views/widgets/GeoPointWidget.java
📚 Learning: viewmodels should not store view or activity references as this can cause memory leaks. unlike fragm...
Learnt from: shubham1g5
PR: dimagi/commcare-android#3042
File: app/src/org/commcare/fragments/BreadcrumbBarViewModel.java:50-55
Timestamp: 2025-04-21T15:02:17.492Z
Learning: ViewModels should not store View or Activity references as this can cause memory leaks. Unlike Fragments with setRetainInstance(true), ViewModels don't have automatic view detachment mechanisms. When migrating from Fragments to ViewModels, view references should be replaced with data-only state in the ViewModel.

Applied to files:

  • app/src/org/commcare/activities/EntitySelectActivity.java
📚 Learning: in commcaresetupactivity.java, the call to installfragment.showconnecterrormessage() after fragment ...
Learnt from: OrangeAndGreen
PR: dimagi/commcare-android#3121
File: app/src/org/commcare/activities/CommCareSetupActivity.java:360-364
Timestamp: 2025-05-22T14:28:35.959Z
Learning: In CommCareSetupActivity.java, the call to installFragment.showConnectErrorMessage() after fragment transactions is intentionally unguarded with null checks. This follows the app's design pattern where critical error paths prefer immediate crashes over silent failures, making potential issues immediately visible during development rather than hiding them with defensive programming.

Applied to files:

  • app/src/org/commcare/activities/EntitySelectActivity.java
  • app/src/org/commcare/views/widgets/GeoPointWidget.java
📚 Learning: never instantiate android activity classes directly with 'new'. activities should only be created th...
Learnt from: OrangeAndGreen
PR: dimagi/commcare-android#3037
File: app/src/org/commcare/connect/ConnectIDManager.java:233-243
Timestamp: 2025-04-22T15:48:29.346Z
Learning: Never instantiate Android Activity classes directly with 'new'. Activities should only be created through the Android framework using Intents.

Applied to files:

  • app/src/org/commcare/activities/EntitySelectActivity.java
  • app/src/org/commcare/views/widgets/GeoPointWidget.java
📚 Learning: never instantiate android activity classes directly with 'new' as it bypasses the android component ...
Learnt from: OrangeAndGreen
PR: dimagi/commcare-android#3037
File: app/src/org/commcare/connect/ConnectIDManager.java:233-243
Timestamp: 2025-04-22T15:48:29.346Z
Learning: Never instantiate Android Activity classes directly with 'new' as it bypasses the Android component lifecycle. Activities should only be created by the system through Intents. Non-static instance fields don't need manual resetting as they'll be initialized with their default values when a new activity instance is properly created.

Applied to files:

  • app/src/org/commcare/activities/EntitySelectActivity.java
📚 Learning: in selectinstallmodefragment.java, the showconnecterrormessage method intentionally omits null check...
Learnt from: OrangeAndGreen
PR: dimagi/commcare-android#3121
File: app/src/org/commcare/fragments/SelectInstallModeFragment.java:201-205
Timestamp: 2025-05-22T14:26:41.341Z
Learning: In SelectInstallModeFragment.java, the showConnectErrorMessage method intentionally omits null checks because it's called at a specific point in the startup flow where UI is guaranteed to be loaded. It's designed to crash if activity or view is null to make potential issues immediately visible rather than hiding them with defensive programming.

Applied to files:

  • app/src/org/commcare/activities/EntitySelectActivity.java
📚 Learning: in connectunlockfragment.java, the user prefers to let getarguments() potentially throw nullpointere...
Learnt from: OrangeAndGreen
PR: dimagi/commcare-android#3108
File: app/src/org/commcare/fragments/connect/ConnectUnlockFragment.java:62-64
Timestamp: 2025-06-04T19:17:21.213Z
Learning: In ConnectUnlockFragment.java, the user prefers to let getArguments() potentially throw NullPointerException rather than adding null checks, as the arguments are required for proper navigation flow and their absence indicates a programming error that should fail fast.

Applied to files:

  • app/src/org/commcare/activities/EntitySelectActivity.java
📚 Learning: in the commcare android codebase, use org.jetbrains.annotations.notnull for null-safety annotations....
Learnt from: OrangeAndGreen
PR: dimagi/commcare-android#2912
File: app/src/org/commcare/android/database/connect/models/ConnectUserRecord.java:81-89
Timestamp: 2025-01-21T17:27:58.754Z
Learning: In the CommCare Android codebase, use org.jetbrains.annotations.NotNull for null-safety annotations. Empty strings are acceptable for unspecified values, but null values should be prevented using NotNull.

Applied to files:

  • app/src/org/commcare/activities/EntitySelectActivity.java
  • app/src/org/commcare/location/CommCareFusedLocationController.kt
📚 Learning: the connect base url and api version in build.gradle are intentionally hardcoded as these values do ...
Learnt from: pm-dimagi
PR: dimagi/commcare-android#2847
File: app/build.gradle:294-295
Timestamp: 2025-01-27T15:18:25.903Z
Learning: The Connect base URL and API version in build.gradle are intentionally hardcoded as these values do not change with variants.

Applied to files:

  • app/build.gradle
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Lint Code Base
🔇 Additional comments (3)
app/src/org/commcare/activities/EntitySelectActivity.java (1)

777-779: LGTM! Clean simplification removing Mapbox dependency.

The conditional logic for selecting between Mapbox and non-Mapbox map activities has been properly removed, now always using EntityMapActivity. This change aligns well with the overall Mapbox library removal effort.

app/src/org/commcare/views/widgets/GeoPointWidget.java (1)

139-141: LGTM! Method simplified by removing Mapbox conditional logic.

The getMapActivityIntent() method has been appropriately simplified to always return GeoPointMapActivity, removing the previous conditional logic that selected between Mapbox and non-Mapbox implementations. This change is consistent with the overall Mapbox library removal effort.

app/build.gradle (1)

89-89: Google Play Services Location dependency is up-to-date (21.3.0) with no known security advisories
Verified that 21.3.0 is the latest stable version as of August 2025 and no documented vulnerabilities exist. No changes needed—continue monitoring Google’s release notes for future updates.

@avazirna avazirna marked this pull request as ready for review August 7, 2025 17:18
@avazirna avazirna added this to the 2.59 milestone Aug 7, 2025
@avazirna avazirna requested a review from shubham1g5 August 7, 2025 19:16
Copy link
Contributor

@shubham1g5 shubham1g5 left a comment

Choose a reason for hiding this comment

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

thanks for the detailed description over there.

@shubham1g5 shubham1g5 merged commit 8e90d73 into master Aug 8, 2025
4 of 11 checks passed
@shubham1g5 shubham1g5 deleted the remove-kujaku branch August 8, 2025 12:21
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.

3 participants