Skip to content

Fix #6179 and Fix #6272: Play Age Signals Integration[Blocked on #6239] - #6456

Open
adhiamboperes wants to merge 9 commits into
developfrom
play-age-signals-integration
Open

adhiamboperes wants to merge 9 commits into
developfrom
play-age-signals-integration

Conversation

@adhiamboperes

@adhiamboperes adhiamboperes commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Explanation

Fixes #6179

Fixes #6272

This PR integrates Google Play Age Signals SDK 0.0.3 into app's startup. It adds the ability to request age-related information from Google Play as part of the work to support regulatory requirements in Brazil and Texas. The integration does not introduce age-verification screens, restrict access to lessons, or change app behavior based on the returned signals.

The new AgeSignalsController lives in the domain layer and implements ApplicationStartupListener. It starts an asynchronous request after application initialization has completed. The manager is injected through a Provider, so creating the startup listener does not immediately initialize the Play SDK. The existing startup framework invokes this callback once per application process, and the request does not block the remaining startup listeners while waiting for a response.

Successful responses are discarded without reading or storing age ranges, installation IDs, or parental-approval information. Asynchronous failures, synchronous runtime exceptions, and linkage errors are handled so that unavailable or incompatible Google components do not prevent normal app use.

The dependency changes add both the Age Signals SDK and an explicit Play Services Tasks dependency, together with the corresponding Maven lockfile and license metadata updates. Declaring Tasks directly allows the controller and tests to use its APIs under Bazel’s strict dependency visibility.

The new AgeSignalsControllerTest uses FakeAgeSignalsManager for normal responses and documented API errors. A small test-only adapter, TestAgeSignalsManager, adds control over pending requests, synchronous failures, and request counts without contacting Google Play or using mocks.

The behaviour tested:

  • Deferring manager creation until initialization completes.
  • Returning without waiting for a pending request and handling delayed completion.
  • Verified, declared, supervised, pending-approval, denied-approval, unknown, and null responses.
  • Documented failures, including unavailable Play components, network errors, outdated versions, and apps not owned through Play.
  • Continuing to subsequent startup listeners after failures and checking the expected diagnostic messages.
    The in-app privacy policy now describes Oppia’s temporary, local handling of age signals and explicitly excludes their use for advertising, profiling, or analytics. It also distinguishes Oppia’s handling of returned signals from Google Play’s own processing.

Some additional notes:

  • This implements signal retrieval. A successful callback can contain an empty response.
  • A matching website privacy-policy update need to be done seperately on Oppia Web.

Essential Checklist

  • The PR title starts with "Fix #bugnum: " (If this PR fixes part of an issue, prefix the title with "Fix part of #bugnum: ...".)
  • The explanation section above starts with "Fixes #bugnum: " (If this PR fixes part of an issue, use instead: "Fixes part of #bugnum: ...".)
  • Any changes to scripts/assets files have their rationale included in the PR explanation.
  • The PR follows the style guide.
  • The PR does not contain any unnecessary code changes from Android Studio (reference).
  • The PR is made from a branch that's not called "develop" and is up-to-date with "develop".
  • The PR is assigned to the appropriate reviewers (reference).

Disclosure of LLM Usage

Output

When the app is launched, the learner should be able to proceed regardless of the outcome of the age signals request. The app will retry during a subsequent startup.

Successful Request
Screenshot 2026-09-16 at 10 43 22

Failed Request due to Device Missing Google Play Services
Screenshot 2026-09-16 at 10 37 50

@adhiamboperes adhiamboperes self-assigned this Sep 15, 2026
Comment thread domain/src/test/AndroidManifest.xml Resolved
@adhiamboperes
adhiamboperes marked this pull request as ready for review September 16, 2026 08:06
@adhiamboperes
adhiamboperes requested review from a team as code owners September 16, 2026 08:06
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report

Results

Number of files assessed: 6
Overall Coverage: 100.00%
Coverage Analysis: FAIL ❌

Failure Cases

File Failure Reason Status
AgeSignalsModule.ktdomain/src/main/java/org/oppia/android/domain/agesignals/AgeSignalsModule.kt
No appropriate test file found for domain/src/main/java/org/oppia/android/domain/agesignals/AgeSignalsModule.kt. ❌

Passing coverage

Files with passing code coverage
File Coverage Lines Hit Status Min Required
AgeSignalsController.ktdomain/src/main/java/org/oppia/android/domain/agesignals/AgeSignalsController.kt
100.00% 19 / 19 ✅ 70%

Exempted coverage

Files exempted from coverage
File Exemption Reason
GaApplicationComponent.ktapp/src/main/java/org/oppia/android/app/application/ga/GaApplicationComponent.kt
This file is exempted from having a test file; skipping coverage check.
DeveloperApplicationComponent.ktapp/src/main/java/org/oppia/android/app/application/dev/DeveloperApplicationComponent.kt
This file is exempted from having a test file; skipping coverage check.
AlphaApplicationComponent.ktapp/src/main/java/org/oppia/android/app/application/alpha/AlphaApplicationComponent.kt
This file is exempted from having a test file; skipping coverage check.
BetaApplicationComponent.ktapp/src/main/java/org/oppia/android/app/application/beta/BetaApplicationComponent.kt
This file is exempted from having a test file; skipping coverage check.

Refer test_file_exemptions.textproto for the comprehensive list of file exemptions and their required coverage percentages.

To learn more, visit the Oppia Android Code Coverage wiki page

@Neer-rn Neer-rn left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This PR is taking me quite a bit of time to review even for the simplest parts, and there are several parts of the Age Signals integration that I don’t fully understand yet. I will pass on this review for now and assign it to @Sandesh282 to take the first pass.

@Neer-rn Neer-rn assigned Sandesh282 and unassigned Neer-rn Sep 17, 2026

@Sandesh282 Sandesh282 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@adhiamboperes Overall the design sounds right. I have some nits though.

.addOnFailureListener { exception ->
oppiaLogger.e("AgeSignalsController", "Failed to ingest age signals", exception)
}
} catch (e: RuntimeException) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The comment says "Catching Throwable" but the catch is RuntimeException. Also "missing classes on non-GMS devices" would throw NoClassDefFoundError, which is a LinkageError, which is already handled by the separate catch (e: LinkageError) below. The comment is misleading. Should be something like: "Catching RuntimeException to guard against unexpected failures from the Play SDK call itself."

@@ -0,0 +1,390 @@
package org.oppia.android.domain.agesignals

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The TestAgeSignalsManager has both creationCount and creationFailure properties, suggesting the intent was to test Provider-level initialization failures (i.e., when ageSignalsManagerProvider.get() itself throws). There's no test exercising this path. A test like testCompletedInitialization_managerCreationFails_doesNotCrash would complete the coverage for the LinkageError path at Provider construction time vs. at checkAgeSignals() call time.

@oppiabot

oppiabot Bot commented Sep 17, 2026

Copy link
Copy Markdown

Unassigning @Sandesh282 since the review is done.

@oppiabot

oppiabot Bot commented Sep 17, 2026

Copy link
Copy Markdown

Hi @adhiamboperes, it looks like some changes were requested on this pull request by @Sandesh282. PTAL. Thanks!

@adhiamboperes adhiamboperes changed the title Fix #6179 and Fix #6272: Play Age Signals Integration Fix #6179 and Fix #6272: Play Age Signals Integration[Blocked on #6239] Sep 18, 2026
@oppiabot

oppiabot Bot commented Sep 25, 2026

Copy link
Copy Markdown

Hi @adhiamboperes, I'm going to mark this PR as stale because it hasn't had any updates for 7 days. If no further activity occurs within 7 days, it will be automatically closed so that others can take up the issue.
If you are still working on this PR, please make a follow-up commit within 3 days (and submit it for review, if applicable). Please also let us know if you are stuck so we can help you! If you're unsure how to reassign this PR to a reviewer, please make sure to review the wiki page that details the Guidance on submitting PRs.

@oppiabot oppiabot Bot added the stale Corresponds to items that haven't seen a recent update and may be automatically closed. label Sep 25, 2026
@adhiamboperes adhiamboperes removed the stale Corresponds to items that haven't seen a recent update and may be automatically closed. label Sep 25, 2026
@oppiabot

oppiabot Bot commented Oct 2, 2026

Copy link
Copy Markdown

Hi @adhiamboperes, I'm going to mark this PR as stale because it hasn't had any updates for 7 days. If no further activity occurs within 7 days, it will be automatically closed so that others can take up the issue.
If you are still working on this PR, please make a follow-up commit within 3 days (and submit it for review, if applicable). Please also let us know if you are stuck so we can help you! If you're unsure how to reassign this PR to a reviewer, please make sure to review the wiki page that details the Guidance on submitting PRs.

@oppiabot oppiabot Bot added the stale Corresponds to items that haven't seen a recent update and may be automatically closed. label Oct 2, 2026
@adhiamboperes adhiamboperes removed the stale Corresponds to items that haven't seen a recent update and may be automatically closed. label Oct 7, 2026
@oppiabot

oppiabot Bot commented Oct 15, 2026

Copy link
Copy Markdown

Hi @adhiamboperes, I'm going to mark this PR as stale because it hasn't had any updates for 7 days. If no further activity occurs within 7 days, it will be automatically closed so that others can take up the issue.
If you are still working on this PR, please make a follow-up commit within 3 days (and submit it for review, if applicable). Please also let us know if you are stuck so we can help you! If you're unsure how to reassign this PR to a reviewer, please make sure to review the wiki page that details the Guidance on submitting PRs.

@oppiabot oppiabot Bot added the stale Corresponds to items that haven't seen a recent update and may be automatically closed. label Oct 15, 2026
@adhiamboperes adhiamboperes removed the stale Corresponds to items that haven't seen a recent update and may be automatically closed. label Oct 21, 2026
@BenHenning

Copy link
Copy Markdown
Member

@adhiamboperes is there a discussion anywhere that explains why this is blocked on #6239? From what I can tell this PR builds and the app runs with it. That almost certainly means that there isn't actually a requirement to upgrade AndroidX Core here. Am I missing something?

@adhiamboperes

Copy link
Copy Markdown
Contributor Author

@BenHenning, you can see that the prod flavors of the app failed to build. The Builds on this PR have expired, but please see this gist: https://gist.github.com/adhiamboperes/fdb08bd84fcac546e86fd2e68c2f6d5a for the Proguard error produced.

@adhiamboperes

adhiamboperes commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor Author

In third_party/maven_install.json:

  • play-services-basement was updated from 18.0.0 to 18.9.0.
  • play-services-tasks was updated from 18.0.1 to 18.2.0.

What I got from MVNRepository:

Play Services Basement 18.0.2
View dependencies
Play Services Basement 18.9.0
View dependencies
androidx.collection:collection:1.0.0
androidx.core:core:1.2.0
androidx.fragment:fragment:1.0.0
androidx.collection:collection:1.0.0
androidx.core:core:1.2.0
androidx.fragment:fragment:1.1.0
Play Services Tasks 18.0.2
View dependencies
Play Services Tasks 18.2.0
View dependencies
com.google.android.gms:play-services-basement:18.1.0 com.google.android.gms:play-services-basement:18.4.0

Age Signals 0.0.3

View dependencies

  • com.google.android.gms:play-services-basement:18.9.0
  • com.google.android.gms:play-services-tasks:18.2.0
  • com.google.android.play:core-common:2.0.4

Edit: TL;DR Age Signals is declaring basement 18.9.0 which references PendingIntentCompat and BuildCompat.isAtLeastV(), and these classes are not in our current version of core.

@BenHenning

Copy link
Copy Markdown
Member

Thanks @adhiamboperes. There's definitely something finicky going on because those dependencies are supposed to resolve through Maven (but I'm assuming there's some historical bad decisions coming out here from the way Play Services is designed, but I digress). It's good that Proguard is catching the issue.

The problem seems to be that we need an AndroidX Core version new enough to include both BuildCompat.isAtLeastV() and PendingIntentCompat which I traced to 1.13.0. Unfortunately, depending on that still bumps our stdlib to 1.8 (same issue as the 1.16.0 androidx.core version). I was able to use Claude to upgrade the codebase to Kotlin 1.7 as a proof-of-concept and it did get the Proguard build working. Unfortunately, it really bleeds out into a lot more than I think we're comfortable with.

My thoughts are that we fortunately do not actually need Bazel 7 for the AndroidX Core upgrade, but we do need at least Kotlin 1.7. I think we should prioritize #6234 and #6235 first, and then we'll need one more change on those 2 for the AndroidX Core upgrade (note: #6236 may also end up being needed for some complex dependency reasons), in order to unblock this change. I've reopened the first PR with it being up-to-date with the latest develop to see how CI shakes out. I was originally going to put more in that PR ahead of the Bazel 7 chain but I'm thinking instead that I'll work to finalize that PR and get it into review and then turn my attention to the others (which should actually be easier). Unfortunately it will probably take a few weeks to get all of these built and merged with my current availability, but this is a pathway forward.

@oppiabot

oppiabot Bot commented Oct 30, 2026

Copy link
Copy Markdown

Hi @adhiamboperes, I'm going to mark this PR as stale because it hasn't had any updates for 7 days. If no further activity occurs within 7 days, it will be automatically closed so that others can take up the issue.
If you are still working on this PR, please make a follow-up commit within 3 days (and submit it for review, if applicable). Please also let us know if you are stuck so we can help you! If you're unsure how to reassign this PR to a reviewer, please make sure to review the wiki page that details the Guidance on submitting PRs.

@oppiabot oppiabot Bot added the stale Corresponds to items that haven't seen a recent update and may be automatically closed. label Oct 30, 2026
@adhiamboperes adhiamboperes removed the stale Corresponds to items that haven't seen a recent update and may be automatically closed. label Nov 2, 2026
@BenHenning

Copy link
Copy Markdown
Member

Confirming that we probably will actually need to depend on #6236 unfortunately (the version of R8 we're using causes some issues when trying to upgrade AndroidX).

This branch has not been deployed

No deployments
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.

[Feature Request]: Integrate Google Play Age Signals API for Texas SB 2420 [Feature Request]: Depend on Play Age Signals API

6 participants