Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8f7d732
Rebuild app & WorkManager initialization.
BenHenning Jan 2, 2026
9e0a9e8
Some job cleanup work.
BenHenning Feb 21, 2026
cc57180
Upgrade work manager.
BenHenning Feb 21, 2026
1d439a7
Core threading utility fixes.
BenHenning Feb 21, 2026
cc3ab25
Add core work manager utility tests.
BenHenning Feb 21, 2026
1d42d3d
Undo WorkManager version upgrade.
BenHenning Feb 22, 2026
6a2e3ca
Add tests for MetricLogSchedulingWorker.
BenHenning Feb 22, 2026
5287c61
Add tests for LogUploadWorker.
BenHenning Feb 23, 2026
7fed12a
Add tests for PlatformParameterSyncUpWorker.
BenHenning Feb 23, 2026
468941e
Add a bunch of KDocs.
BenHenning Feb 23, 2026
d85d996
Merge branch 'develop' into fix-work-manager-and-app-init
BenHenning Feb 25, 2026
a389e76
Post-merge fix.
BenHenning Feb 25, 2026
7df00b3
Fix parameter synchronizing on main thread.
BenHenning Feb 25, 2026
95f946f
Fix most tests.
BenHenning Feb 25, 2026
5ec94c2
Other half of fixing most tests.
BenHenning Feb 25, 2026
6a64f62
Fix KDoc check.
BenHenning Feb 26, 2026
8fcf0a1
Remove unnecessary work-testing deps.
BenHenning Feb 26, 2026
0050fcb
Significantly reduced WorkManager testing surface.
BenHenning Feb 26, 2026
2f2c295
Rebuild OppiaWorkManagerTestDriver's API.
BenHenning Feb 27, 2026
da1dc06
Add & fix KDocs.
BenHenning Feb 27, 2026
1c24660
Regex fixes plus removed some TODOs.
BenHenning Feb 27, 2026
2ce2f31
Undo all threading related testing.
BenHenning Feb 27, 2026
1ba8f48
Fix formatting errors.
BenHenning Feb 27, 2026
c23fe5d
Undo breakage.
BenHenning Feb 27, 2026
c37f8a9
Fix final broken tests.
BenHenning Feb 28, 2026
59788c9
Merge branch 'develop' into fix-work-manager-and-app-init
BenHenning Feb 28, 2026
533b988
Merge branch 'develop' into fix-work-manager-and-app-init
BenHenning Mar 20, 2026
b8b527a
Address reviewer comments.
BenHenning Mar 20, 2026
eefa4ed
Finish wiki section.
BenHenning Mar 21, 2026
6d2e806
Merge branch 'develop' into fix-work-manager-and-app-init
BenHenning Mar 25, 2026
491f8e5
Address self-review comments.
BenHenning Mar 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 2 additions & 1 deletion app/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ kt_android_library(
"//third_party:androidx_databinding_databinding-common",
"//third_party:androidx_databinding_databinding-runtime",
"//utility",
"//utility/src/main/java/org/oppia/android/util/enumfilter:enum_filter_util",
"//utility/src/main/java/org/oppia/android/util/extensions:context_extensions",
"//utility/src/main/java/org/oppia/android/util/logging/firebase:debug_module",
"//utility/src/main/java/org/oppia/android/util/math:fraction_parser",
Expand Down Expand Up @@ -678,6 +679,7 @@ kt_android_library(
"//third_party:org_jetbrains_kotlin_kotlin-stdlib-jdk8_jar",
"//utility",
"//utility/src/main/java/org/oppia/android/util/extensions:bundle_extensions",
"//utility/src/main/java/org/oppia/android/util/logging:current_app_screen_name_intent_decorator",
"//utility/src/main/java/org/oppia/android/util/parser/image:image_loader",
"//utility/src/main/java/org/oppia/android/util/parser/image:image_parsing_annonations",
"//utility/src/main/java/org/oppia/android/util/profile:current_user_profile_id_intent_decorator",
Expand Down Expand Up @@ -799,7 +801,6 @@ TEST_DEPS = [
"//third_party:androidx_test_espresso_espresso-intents",
"//third_party:androidx_test_ext_junit",
"//third_party:androidx_test_runner",
"//third_party:androidx_work_work-testing",
"//third_party:com_github_bumptech_glide_mocks",
"//third_party:com_google_truth_truth",
"//third_party:org_jetbrains_kotlin_kotlin-reflect",
Expand Down
14 changes: 10 additions & 4 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/OppiaTheme">
<!-- NOTE TO DEVELOPER: You can enable debug logs for fast upload & better inspection in Firebase console using https://support.google.com/analytics/answer/7201382. -->
<!-- NOTE TO DEVELOPER: You can enable debug logs for fast upload & better inspection in Firebase console by using this command: adb shell setprop debug.firebase.analytics.app org.oppia.android -->
<meta-data android:name="firebase_analytics_collection_deactivated" android:value="true" />
<meta-data android:name="firebase_crashlytics_collection_enabled" android:value="false" />
<meta-data
Expand Down Expand Up @@ -370,8 +370,14 @@
android:name=".app.testing.TextInputLayoutBindingAdaptersTestActivity"
android:theme="@style/OppiaThemeWithoutActionBar" />
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
</application>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,29 @@ import android.app.Application
import androidx.appcompat.app.AppCompatActivity
import androidx.multidex.MultiDexApplication
import androidx.work.Configuration
import androidx.work.WorkManager
import com.google.firebase.FirebaseApp
import com.google.firebase.appcheck.AppCheckProviderFactory
import com.google.firebase.appcheck.FirebaseAppCheck
import com.google.firebase.appcheck.debug.DebugAppCheckProviderFactory
import com.google.firebase.appcheck.playintegrity.PlayIntegrityAppCheckProviderFactory
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import org.oppia.android.app.activity.ActivityComponent
import org.oppia.android.app.activity.ActivityComponentFactory
import org.oppia.android.app.model.BuildFlavor
import org.oppia.android.domain.oppialogger.ApplicationStartupListener
import org.oppia.android.util.extensions.safeForEach

/** The root base [Application] of the Oppia app. */
/**
* The root base [Application] of the Oppia app.
*
* @param createComponentBuilder the [ApplicationComponent.Builder] used to construct the root
* Dagger class for the implementation's flavor of the app
* @property firebaseAppCheckProviderFactory the [AppCheckProviderFactory] used when initializing
* FirebaseAppCheck. This is defaulted for production use cases, but implementations may choose
* to provide a different one for improved debugging support.
*/
abstract class AbstractOppiaApplication(
createComponentBuilder: () -> ApplicationComponent.Builder
createComponentBuilder: () -> ApplicationComponent.Builder,
private val firebaseAppCheckProviderFactory: AppCheckProviderFactory =
PlayIntegrityAppCheckProviderFactory.getInstance()
) : MultiDexApplication(),
ActivityComponentFactory,
ApplicationInjectorProvider,
Expand All @@ -42,48 +48,34 @@ abstract class AbstractOppiaApplication(
override fun onCreate() {
super.onCreate()

// Platform parameter initialization must happen very early since even workers can use both
// feature flags and platform parameters.
component.getPlatformParameterController().loadParametersAsync().invokeOnCompletion { e ->
if (e != null) {
throw Exception("Failed to initialize platform parameters.", e)
}
// Allow startup listeners to early initialize.
val startupListeners = component.getApplicationStartupListeners()
startupListeners.forEach(ApplicationStartupListener::onCreateStarted)

// Continue initializing the startup state. Due to the asynchronous nature of platform
// parameter initialization, this happens after onCreate() finishes at the application level.
// This can introduce some inconsistencies in SplashActivity, though by the time
// SplashActivity completes the following should be fully initialized.
CoroutineScope(Dispatchers.Main).async {
FirebaseApp.initializeApp(applicationContext)
// FirebaseAppCheck protects our API resources from abuse. It works with Firebase
// services, Google Cloud services, and can also be implemented for our own APIs. See
// https://firebase.google.com/docs/app-check for currently supported Firebase products.
// Note that as of this code being checked in, only the app's Firestore usage is affected
// by App Check (Analytics is NOT affected).
if (component.getCurrentBuildFlavor() == BuildFlavor.DEVELOPER) {
FirebaseAppCheck.getInstance().installAppCheckProviderFactory(
DebugAppCheckProviderFactory.getInstance(),
)
} else {
FirebaseAppCheck.getInstance().installAppCheckProviderFactory(
PlayIntegrityAppCheckProviderFactory.getInstance(),
)
}
WorkManager.initialize(applicationContext, workManagerConfiguration)
val workManager = WorkManager.getInstance(applicationContext)
component.getAnalyticsStartupListenerStartupListeners().safeForEach {
it.onCreate(workManager)
}
component.getApplicationStartupListeners().forEach(ApplicationStartupListener::onCreate)
}.invokeOnCompletion {
if (it != null) {
throw Exception("Failed to continue application initialization.", it)
}
}
// Initialize high-level third-party systems. Note that WorkManager doesn't need to be
// initialized here because it will automatically initialize itself due to the application being
// a Configuration provider.
FirebaseApp.initializeApp(applicationContext)
// FirebaseAppCheck protects our API resources from abuse. It works with Firebase
// services, Google Cloud services, and can also be implemented for our own APIs. See
// https://firebase.google.com/docs/app-check for currently supported Firebase products.
// Note that as of this code being checked in, only the app's Firestore usage is affected
// by App Check (Analytics is NOT affected).
FirebaseAppCheck.getInstance().installAppCheckProviderFactory(firebaseAppCheckProviderFactory)

// Kick off a background task to finish startup initialization. Nothing at this stage should be
// startup-state sensitive. It's also fine for parameters to not be fully initialized at this
// point because each app entry point already accounts for potentially uninitialized parameters:
// splash, direct activity recreation, and waking up the app to kick off a worker. Finally,
// since this is using 'launch' any uncaught exceptions should correctly trigger a failure in
// app startup (which is ideal in this case because we can't reliably and safely start the app).
CoroutineScope(component.getBackgroundDispatcher()).launch {
// Wait for parameters to load before running any startup routines that may depend on them.
component.getPlatformParameterController().loadParametersAsync().await()
startupListeners.forEach(ApplicationStartupListener::onCompletedInitialization)
}
}

override fun getWorkManagerConfiguration(): Configuration {
return component.getWorkManagerConfiguration()
}
override fun getWorkManagerConfiguration(): Configuration =
component.getWorkManagerConfiguration()
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import android.app.Application
import androidx.work.Configuration
import dagger.BindsInstance
import org.oppia.android.app.activity.ActivityComponentImpl
import org.oppia.android.app.model.BuildFlavor
import org.oppia.android.domain.oppialogger.ApplicationStartupListener
import org.oppia.android.domain.oppialogger.analytics.AnalyticsStartupListener
import javax.inject.Provider

/**
Expand All @@ -28,9 +26,5 @@ interface ApplicationComponent : ApplicationInjector {

fun getApplicationStartupListeners(): Set<ApplicationStartupListener>

fun getAnalyticsStartupListenerStartupListeners(): Set<AnalyticsStartupListener>

fun getWorkManagerConfiguration(): Configuration

fun getCurrentBuildFlavor(): BuildFlavor
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ android_library(
"//domain/src/main/java/org/oppia/android/domain/oppialogger/logscheduler:metric_log_scheduler_module",
"//domain/src/main/java/org/oppia/android/domain/oppialogger/loguploader:worker_module",
"//domain/src/main/java/org/oppia/android/domain/platformparameter:prod_module",
"//domain/src/main/java/org/oppia/android/domain/workmanager:work_manager_configuration_module",
"//utility/src/main/java/org/oppia/android/util/accessibility:prod_module",
"//utility/src/main/java/org/oppia/android/util/caching:asset_prod_module",
"//utility/src/main/java/org/oppia/android/util/caching:caching_prod_module",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ import org.oppia.android.util.gcsresource.GcsResourceModule
import org.oppia.android.util.locale.LocaleProdModule
import org.oppia.android.util.logging.LoggerModule
import org.oppia.android.util.logging.SyncStatusModule
import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule
import org.oppia.android.util.logging.firebase.LogReportingModule
import org.oppia.android.util.logging.performancemetrics.PerformanceMetricsAssessorModule
import org.oppia.android.util.logging.performancemetrics.PerformanceMetricsConfigurationsModule
Expand Down Expand Up @@ -85,7 +84,7 @@ import javax.inject.Singleton
RatioInputModule::class, UncaughtExceptionLoggerModule::class,
ApplicationStartupListenerModule::class, LogReportWorkerModule::class,
WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class,
FirebaseLogUploaderModule::class, RetrofitModule::class, RetrofitServiceModule::class,
RetrofitModule::class, RetrofitServiceModule::class,
PlatformParameterModule::class, PlatformParameterSingletonModule::class,
ExplorationStorageModule::class, DeveloperOptionsModule::class,
PlatformParameterSyncUpWorkerModule::class, NetworkConfigProdModule::class, AssetModule::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ import org.oppia.android.util.gcsresource.GcsResourceModule
import org.oppia.android.util.locale.LocaleProdModule
import org.oppia.android.util.logging.LoggerModule
import org.oppia.android.util.logging.SyncStatusModule
import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule
import org.oppia.android.util.logging.firebase.LogReportingModule
import org.oppia.android.util.logging.performancemetrics.PerformanceMetricsAssessorModule
import org.oppia.android.util.logging.performancemetrics.PerformanceMetricsConfigurationsModule
Expand Down Expand Up @@ -85,7 +84,7 @@ import javax.inject.Singleton
RatioInputModule::class, UncaughtExceptionLoggerModule::class,
ApplicationStartupListenerModule::class, LogReportWorkerModule::class,
WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class,
FirebaseLogUploaderModule::class, RetrofitModule::class, RetrofitServiceModule::class,
RetrofitModule::class, RetrofitServiceModule::class,
PlatformParameterModule::class, PlatformParameterSingletonModule::class,
ExplorationStorageModule::class, DeveloperOptionsModule::class,
PlatformParameterSyncUpWorkerModule::class, NetworkConfigProdModule::class, AssetModule::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ kt_android_library(
"//app/src/main/java/org/oppia/android/app/application:common_application_modules",
"//domain/src/main/java/org/oppia/android/domain/auth:auth_module",
"//domain/src/main/java/org/oppia/android/domain/platformparameter:debug_module",
"//domain/src/main/java/org/oppia/android/domain/workmanager/debug:debug_module",
"//third_party:com_google_firebase_firebase-common",
"//utility/src/main/java/org/oppia/android/util/logging/firebase:debug_module",
"//utility/src/main/java/org/oppia/android/util/networking:debug_module",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import org.oppia.android.domain.platformparameter.PlatformParameterSingletonModu
import org.oppia.android.domain.platformparameter.syncup.PlatformParameterSyncUpWorkerModule
import org.oppia.android.domain.question.QuestionModule
import org.oppia.android.domain.workmanager.WorkManagerConfigurationModule
import org.oppia.android.domain.workmanager.debug.DebugWorkerDebugModule
import org.oppia.android.util.accessibility.AccessibilityProdModule
import org.oppia.android.util.caching.AssetModule
import org.oppia.android.util.caching.CachingModule
Expand All @@ -54,7 +55,6 @@ import org.oppia.android.util.locale.LocaleProdModule
import org.oppia.android.util.logging.LoggerModule
import org.oppia.android.util.logging.SyncStatusModule
import org.oppia.android.util.logging.firebase.DebugLogReportingModule
import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule
import org.oppia.android.util.logging.performancemetrics.PerformanceMetricsAssessorModule
import org.oppia.android.util.logging.performancemetrics.PerformanceMetricsConfigurationsModule
import org.oppia.android.util.networking.NetworkConnectionDebugUtilModule
Expand Down Expand Up @@ -87,7 +87,7 @@ import javax.inject.Singleton
UncaughtExceptionLoggerModule::class, ApplicationStartupListenerModule::class,
LogReportWorkerModule::class, WorkManagerConfigurationModule::class,
HintsAndSolutionConfigModule::class, HintsAndSolutionDebugModule::class,
FirebaseLogUploaderModule::class, RetrofitModule::class, RetrofitServiceModule::class,
RetrofitModule::class, RetrofitServiceModule::class,
PlatformParameterSingletonModule::class, PlatformParameterDebugModule::class,
ExplorationStorageModule::class, DeveloperOptionsStarterModule::class,
DeveloperOptionsModule::class, PlatformParameterSyncUpWorkerModule::class,
Expand All @@ -101,7 +101,7 @@ import javax.inject.Singleton
PerformanceMetricsAssessorModule::class, PerformanceMetricsConfigurationsModule::class,
DeveloperBuildFlavorModule::class,
CpuPerformanceSnapshotterModule::class, ExplorationProgressModule::class,
AuthenticationModule::class
AuthenticationModule::class, DebugWorkerDebugModule::class
]
)
interface DeveloperApplicationComponent : ApplicationComponent {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.oppia.android.app.application.dev

import com.google.firebase.appcheck.debug.DebugAppCheckProviderFactory
import org.oppia.android.app.application.AbstractOppiaApplication

/** The root [AbstractOppiaApplication] for developer builds of the Oppia app. */
class DeveloperOppiaApplication : AbstractOppiaApplication(
DaggerDeveloperApplicationComponent::builder
DaggerDeveloperApplicationComponent::builder,
firebaseAppCheckProviderFactory = DebugAppCheckProviderFactory.getInstance()
)
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ import org.oppia.android.util.gcsresource.GcsResourceModule
import org.oppia.android.util.locale.LocaleProdModule
import org.oppia.android.util.logging.LoggerModule
import org.oppia.android.util.logging.SyncStatusModule
import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule
import org.oppia.android.util.logging.firebase.LogReportingModule
import org.oppia.android.util.logging.performancemetrics.PerformanceMetricsAssessorModule
import org.oppia.android.util.logging.performancemetrics.PerformanceMetricsConfigurationsModule
Expand Down Expand Up @@ -85,7 +84,7 @@ import javax.inject.Singleton
RatioInputModule::class, UncaughtExceptionLoggerModule::class,
ApplicationStartupListenerModule::class, LogReportWorkerModule::class,
WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class,
FirebaseLogUploaderModule::class, RetrofitModule::class, RetrofitServiceModule::class,
RetrofitModule::class, RetrofitServiceModule::class,
PlatformParameterModule::class, PlatformParameterSingletonModule::class,
ExplorationStorageModule::class, DeveloperOptionsModule::class,
PlatformParameterSyncUpWorkerModule::class, NetworkConfigProdModule::class, AssetModule::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ import org.oppia.android.util.locale.LocaleProdModule
import org.oppia.android.util.logging.CurrentAppScreenNameIntentDecorator.extractCurrentAppScreenName
import org.oppia.android.util.logging.LoggerModule
import org.oppia.android.util.logging.SyncStatusModule
import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule
import org.oppia.android.util.networking.NetworkConnectionDebugUtilModule
import org.oppia.android.util.networking.NetworkConnectionUtilDebugModule
import org.oppia.android.util.parser.html.HtmlParserEntityTypeModule
Expand Down Expand Up @@ -1082,7 +1081,6 @@ class AdministratorControlsActivityTest {
ExplorationProgressModule::class,
ExplorationStorageModule::class,
FakeOppiaClockModule::class,
FirebaseLogUploaderModule::class,
FractionInputModule::class,
GcsResourceModule::class,
GlideImageLoaderModule::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ import org.oppia.android.util.gcsresource.GcsResourceModule
import org.oppia.android.util.locale.LocaleProdModule
import org.oppia.android.util.logging.LoggerModule
import org.oppia.android.util.logging.SyncStatusModule
import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule
import org.oppia.android.util.networking.NetworkConnectionDebugUtilModule
import org.oppia.android.util.networking.NetworkConnectionUtilDebugModule
import org.oppia.android.util.parser.html.HtmlParserEntityTypeModule
Expand Down Expand Up @@ -805,7 +804,6 @@ class AdministratorControlsFragmentTest {
ExplorationProgressModule::class,
ExplorationStorageModule::class,
FakeOppiaClockModule::class,
FirebaseLogUploaderModule::class,
FractionInputModule::class,
GcsResourceModule::class,
GlideImageLoaderModule::class,
Expand Down
Loading
Loading