diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 9cc32896072..16a987aba18 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -658,6 +658,7 @@ kt_android_library( "//app/src/main/java/org/oppia/android/app/fragment:injectable_fragment", "//app/src/main/java/org/oppia/android/app/shim:prod_modules", "//app/src/main/java/org/oppia/android/app/testing/activity:test_activity", + "//app/src/main/java/org/oppia/android/app/utility/edgetoedge:edge_to_edge_helper", "//domain/src/main/java/org/oppia/android/domain/onboarding:state_controller", "//domain/src/main/java/org/oppia/android/domain/oppialogger:startup_listener", "//domain/src/main/java/org/oppia/android/domain/profile:profile_management_controller", @@ -758,6 +759,7 @@ TEST_DEPS = [ "//app/src/main/java/org/oppia/android/app/application/testing:testing_build_flavor_module", "//app/src/main/java/org/oppia/android/app/testing/activity:test_activity", "//app/src/main/java/org/oppia/android/app/translation/testing:test_module", + "//app/src/main/java/org/oppia/android/app/utility/edgetoedge:edge_to_edge_helper", "//app/src/main/java/org/oppia/android/app/utility/math:math_expression_accessibility_util", "//config/src/java/org/oppia/android/config:all_languages_config", "//data/src/main/java/org/oppia/android/data/backends/gae/testing:network_config_test_module", diff --git a/app/src/main/java/org/oppia/android/app/administratorcontrols/AdministratorControlsActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/administratorcontrols/AdministratorControlsActivityPresenter.kt index a7095bc04f3..1674e711b57 100644 --- a/app/src/main/java/org/oppia/android/app/administratorcontrols/AdministratorControlsActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/administratorcontrols/AdministratorControlsActivityPresenter.kt @@ -16,7 +16,10 @@ import org.oppia.android.app.settings.profile.ProfileEditFragment import org.oppia.android.app.settings.profile.ProfileListFragment import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.util.extensions.putProto +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.CurrentUserProfileIdIntentDecorator.decorateWithUserProfileId import javax.inject.Inject @@ -24,7 +27,8 @@ import javax.inject.Inject @ActivityScope class AdministratorControlsActivityPresenter @Inject constructor( private val activity: AppCompatActivity, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var navigationDrawerFragment: NavigationDrawerFragment private var isMultipane = false @@ -42,11 +46,21 @@ class AdministratorControlsActivityPresenter @Inject constructor( selectedProfileId: LegacyProfileId, isProfileDeletionDialogVisible: Boolean ) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } binding = DataBindingUtil.setContentView( activity, R.layout.administrator_controls_activity ) setUpNavigationDrawer() + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToToolbarContainer( + activity, + binding.administratorControlsActivityToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } this.lastLoadedFragment = lastLoadedFragment this.selectedProfileId = selectedProfileId this.isProfileDeletionDialogVisible = isProfileDeletionDialogVisible diff --git a/app/src/main/java/org/oppia/android/app/administratorcontrols/appversion/AppVersionActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/administratorcontrols/appversion/AppVersionActivityPresenter.kt index d57e9fb0656..a1c2358a606 100644 --- a/app/src/main/java/org/oppia/android/app/administratorcontrols/appversion/AppVersionActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/administratorcontrols/appversion/AppVersionActivityPresenter.kt @@ -4,16 +4,32 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [AppVersionActivity]. */ @ActivityScope -class AppVersionActivityPresenter @Inject constructor(private val activity: AppCompatActivity) { +class AppVersionActivityPresenter @Inject constructor( + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue +) { /** Initializes the [AppVersionActivity] views and binds [AppVersionFragment]. */ fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.app_version_activity) - setToolbar() + val toolbar = setToolbar() + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + toolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } if (getAppVersionFragment() == null) { activity.supportFragmentManager.beginTransaction().add( R.id.app_version_fragment_placeholder, @@ -22,10 +38,11 @@ class AppVersionActivityPresenter @Inject constructor(private val activity: AppC } } - private fun setToolbar() { + private fun setToolbar(): Toolbar { val appVersionToolbar: Toolbar = activity.findViewById(R.id.app_version_toolbar) as Toolbar activity.setSupportActionBar(appVersionToolbar) activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) + return appVersionToolbar } private fun getAppVersionFragment(): AppVersionFragment? { diff --git a/app/src/main/java/org/oppia/android/app/administratorcontrols/learneranalytics/ProfileAndDeviceIdActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/administratorcontrols/learneranalytics/ProfileAndDeviceIdActivityPresenter.kt index c435f1bfb08..4e9a6b8f2fe 100644 --- a/app/src/main/java/org/oppia/android/app/administratorcontrols/learneranalytics/ProfileAndDeviceIdActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/administratorcontrols/learneranalytics/ProfileAndDeviceIdActivityPresenter.kt @@ -3,16 +3,30 @@ package org.oppia.android.app.administratorcontrols.learneranalytics import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for arranging the UI of [ProfileAndDeviceIdActivity]. */ class ProfileAndDeviceIdActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { /** Handles [ProfileAndDeviceIdActivity]'s creation flow. */ fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.profile_and_device_id_activity) - setToolbar() + val toolbar = setToolbar() + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + toolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } if (getProfileAndDeviceIdFragment() == null) { activity.supportFragmentManager.beginTransaction().add( R.id.profile_and_device_id_fragment_placeholder, @@ -21,10 +35,11 @@ class ProfileAndDeviceIdActivityPresenter @Inject constructor( } } - private fun setToolbar() { - val appVersionToolbar = activity.findViewById(R.id.profile_and_device_id_toolbar) as Toolbar - activity.setSupportActionBar(appVersionToolbar) + private fun setToolbar(): Toolbar { + val toolbar = activity.findViewById(R.id.profile_and_device_id_toolbar) as Toolbar + activity.setSupportActionBar(toolbar) activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) + return toolbar } private fun getProfileAndDeviceIdFragment(): ProfileAndDeviceIdFragment? { diff --git a/app/src/main/java/org/oppia/android/app/classroom/ClassroomListActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/classroom/ClassroomListActivityPresenter.kt index e887df1b8dc..dfda2a1a35d 100644 --- a/app/src/main/java/org/oppia/android/app/classroom/ClassroomListActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/classroom/ClassroomListActivityPresenter.kt @@ -6,13 +6,19 @@ import androidx.appcompat.widget.Toolbar import androidx.drawerlayout.widget.DrawerLayout import org.oppia.android.app.drawer.NavigationDrawerFragment import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** Tag for identifying the [ClassroomListFragment] in transactions. */ private const val TAG_CLASSROOM_LIST_FRAGMENT = "CLASSROOM_LIST_FRAGMENT" /** The presenter for [ClassroomListActivity]. */ -class ClassroomListActivityPresenter @Inject constructor(private val activity: AppCompatActivity) { +class ClassroomListActivityPresenter @Inject constructor( + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue +) { private var navigationDrawerFragment: NavigationDrawerFragment? = null /** @@ -20,8 +26,18 @@ class ClassroomListActivityPresenter @Inject constructor(private val activity: A * and adds the [ClassroomListFragment] if it's not already added. */ fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.classroom_list_activity) - setUpNavigationDrawer() + val toolbar = setUpNavigationDrawer() + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToToolbarContainer( + activity, + toolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } if (getClassroomListFragment() == null) { activity.supportFragmentManager.beginTransaction().add( R.id.classroom_list_fragment_placeholder, @@ -31,7 +47,7 @@ class ClassroomListActivityPresenter @Inject constructor(private val activity: A } } - private fun setUpNavigationDrawer() { + private fun setUpNavigationDrawer(): Toolbar { val toolbar = activity.findViewById(R.id.classroom_list_activity_toolbar) as Toolbar activity.setSupportActionBar(toolbar) activity.supportActionBar!!.setDisplayShowHomeEnabled(true) @@ -44,6 +60,7 @@ class ClassroomListActivityPresenter @Inject constructor(private val activity: A activity.findViewById(R.id.classroom_list_activity_drawer_layout) as DrawerLayout, toolbar, R.id.nav_home ) + return toolbar } private fun getClassroomListFragment(): ClassroomListFragment? { diff --git a/app/src/main/java/org/oppia/android/app/completedstorylist/CompletedStoryListActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/completedstorylist/CompletedStoryListActivityPresenter.kt index 04ade2649d0..42b8976c98c 100644 --- a/app/src/main/java/org/oppia/android/app/completedstorylist/CompletedStoryListActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/completedstorylist/CompletedStoryListActivityPresenter.kt @@ -4,16 +4,23 @@ import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [CompletedStoryListActivity]. */ @ActivityScope class CompletedStoryListActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { /** Initializes views for [CompletedStoryListActivity] and binds [CompletedStoryListFragment]. */ fun handleOnCreate(profileId: LegacyProfileId) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.completed_story_list_activity) if (getCompletedStoryListFragment() == null) { activity diff --git a/app/src/main/java/org/oppia/android/app/completedstorylist/CompletedStoryListFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/completedstorylist/CompletedStoryListFragmentPresenter.kt index bf94a7dcfcc..5ee5ee7b9c5 100644 --- a/app/src/main/java/org/oppia/android/app/completedstorylist/CompletedStoryListFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/completedstorylist/CompletedStoryListFragmentPresenter.kt @@ -11,6 +11,9 @@ import org.oppia.android.app.databinding.databinding.CompletedStoryListFragmentB import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [CompletedStoryListFragment]. */ @@ -18,7 +21,8 @@ class CompletedStoryListFragmentPresenter @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, private val viewModel: CompletedStoryListViewModel, - private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory + private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var binding: CompletedStoryListFragmentBinding @@ -49,6 +53,14 @@ class CompletedStoryListFragmentPresenter @Inject constructor( it.lifecycleOwner = fragment it.viewModel = viewModel } + + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.completedStoryListToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/devoptions/DeveloperOptionsActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/DeveloperOptionsActivityPresenter.kt index d0fa5b177f4..13e94da3f9b 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/DeveloperOptionsActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/DeveloperOptionsActivityPresenter.kt @@ -8,6 +8,9 @@ import org.oppia.android.app.databinding.databinding.DeveloperOptionsActivityBin import org.oppia.android.app.drawer.NavigationDrawerFragment import org.oppia.android.app.splash.SplashActivity import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject import kotlin.system.exitProcess @@ -17,17 +20,28 @@ const val TAG_FORCE_DOWNLOAD_DIALOG = "FORCE_DOWNLOAD_DIALOG_TAG" /** The presenter for [DeveloperOptionsActivity]. */ @ActivityScope class DeveloperOptionsActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var navigationDrawerFragment: NavigationDrawerFragment private lateinit var binding: DeveloperOptionsActivityBinding fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } binding = DataBindingUtil.setContentView( activity, R.layout.developer_options_activity ) setUpNavigationDrawer() + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToToolbarContainer( + activity, + binding.developerOptionsActivityToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } val previousFragment = getDeveloperOptionsFragment() if (previousFragment == null) { activity.supportFragmentManager.beginTransaction().add( diff --git a/app/src/main/java/org/oppia/android/app/devoptions/featureflags/FeatureFlagsActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/featureflags/FeatureFlagsActivityPresenter.kt index 95205ca201b..367bab55f94 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/featureflags/FeatureFlagsActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/featureflags/FeatureFlagsActivityPresenter.kt @@ -3,16 +3,23 @@ package org.oppia.android.app.devoptions.featureflags import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [FeatureFlagsActivity]. */ @ActivityScope class FeatureFlagsActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { /** Called when [FeatureFlagsActivity] is created. Handles UI for the activity. */ fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp) activity.setContentView(R.layout.feature_flags_activity) diff --git a/app/src/main/java/org/oppia/android/app/devoptions/featureflags/FeatureFlagsFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/featureflags/FeatureFlagsFragmentPresenter.kt index 000b1872bab..43501290ff0 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/featureflags/FeatureFlagsFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/featureflags/FeatureFlagsFragmentPresenter.kt @@ -19,11 +19,14 @@ import org.oppia.android.app.model.OverriddenFeatureFlag import org.oppia.android.app.model.SyncStatus import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.splash.SplashActivity +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.app.view.models.R import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.platformparameter.PlatformParameterControllerDebugImpl import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject import kotlin.system.exitProcess @@ -41,7 +44,8 @@ class FeatureFlagsFragmentPresenter @Inject constructor( private val oppiaLogger: OppiaLogger, private val featureFlagsViewModel: FeatureFlagsViewModel, private val platformParameterControllerDebugImpl: PlatformParameterControllerDebugImpl, - private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory + private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var binding: FeatureFlagsFragmentBinding private lateinit var linearLayoutManager: LinearLayoutManager @@ -95,6 +99,14 @@ class FeatureFlagsFragmentPresenter @Inject constructor( } } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.featureFlagsToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/devoptions/forcenetworktype/ForceNetworkTypeActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/forcenetworktype/ForceNetworkTypeActivityPresenter.kt index c1a55e36ed0..ed4d2a87a24 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/forcenetworktype/ForceNetworkTypeActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/forcenetworktype/ForceNetworkTypeActivityPresenter.kt @@ -3,16 +3,23 @@ package org.oppia.android.app.devoptions.forcenetworktype import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [ForceNetworkTypeActivity]. */ @ActivityScope class ForceNetworkTypeActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { /** Called when [ForceNetworkTypeActivity] is created. Handles UI for the activity. */ fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp) activity.setContentView(R.layout.force_network_type_activity) diff --git a/app/src/main/java/org/oppia/android/app/devoptions/forcenetworktype/ForceNetworkTypeFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/forcenetworktype/ForceNetworkTypeFragmentPresenter.kt index 9e5013e3c24..0c0ddaf7f6b 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/forcenetworktype/ForceNetworkTypeFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/forcenetworktype/ForceNetworkTypeFragmentPresenter.kt @@ -11,7 +11,11 @@ import org.oppia.android.app.databinding.databinding.ForceNetworkTypeFragmentBin import org.oppia.android.app.databinding.databinding.ForceNetworkTypeNetworkItemViewBinding import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.recyclerview.BindableAdapter +import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.util.networking.NetworkConnectionDebugUtil +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [ForceNetworkTypeFragment]. */ @@ -21,7 +25,8 @@ class ForceNetworkTypeFragmentPresenter @Inject constructor( private val fragment: Fragment, private val networkConnectionUtil: Optional, private val forceNetworkTypeViewModel: ForceNetworkTypeViewModel, - private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory + private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var binding: ForceNetworkTypeFragmentBinding @@ -56,6 +61,14 @@ class ForceNetworkTypeFragmentPresenter @Inject constructor( adapter = bindingAdapter } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.forceNetworkTypeToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/devoptions/markchapterscompleted/MarkChaptersCompletedActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/markchapterscompleted/MarkChaptersCompletedActivityPresenter.kt index d01b6e91a1f..cd5cd7a8f88 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/markchapterscompleted/MarkChaptersCompletedActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/markchapterscompleted/MarkChaptersCompletedActivityPresenter.kt @@ -3,15 +3,22 @@ package org.oppia.android.app.devoptions.markchapterscompleted import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [MarkChaptersCompletedActivity]. */ @ActivityScope class MarkChaptersCompletedActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { fun handleOnCreate(internalProfileId: Int, showConfirmationNotice: Boolean) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp) activity.setContentView(R.layout.mark_chapters_completed_activity) diff --git a/app/src/main/java/org/oppia/android/app/devoptions/markchapterscompleted/MarkChaptersCompletedFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/markchapterscompleted/MarkChaptersCompletedFragmentPresenter.kt index 4a480a377a1..1796e6f7db5 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/markchapterscompleted/MarkChaptersCompletedFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/markchapterscompleted/MarkChaptersCompletedFragmentPresenter.kt @@ -16,7 +16,10 @@ import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.devoptions.ModifyLessonProgressController +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [MarkChaptersCompletedFragment]. */ @@ -27,7 +30,8 @@ class MarkChaptersCompletedFragmentPresenter @Inject constructor( private val viewModel: MarkChaptersCompletedViewModel, private val modifyLessonProgressController: ModifyLessonProgressController, private val multiTypeBuilderFactory: BindableAdapter.MultiTypeBuilder.Factory, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var binding: MarkChaptersCompletedFragmentBinding private lateinit var linearLayoutManager: LinearLayoutManager @@ -111,6 +115,14 @@ class MarkChaptersCompletedFragmentPresenter @Inject constructor( } else markChaptersAsCompleted() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.markChaptersCompletedToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/devoptions/markstoriescompleted/MarkStoriesCompletedActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/markstoriescompleted/MarkStoriesCompletedActivityPresenter.kt index 351615fc226..c289d58cd92 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/markstoriescompleted/MarkStoriesCompletedActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/markstoriescompleted/MarkStoriesCompletedActivityPresenter.kt @@ -3,15 +3,22 @@ package org.oppia.android.app.devoptions.markstoriescompleted import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [MarkStoriesCompletedActivity]. */ @ActivityScope class MarkStoriesCompletedActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { fun handleOnCreate(internalProfileId: Int) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp) activity.setContentView(R.layout.mark_stories_completed_activity) diff --git a/app/src/main/java/org/oppia/android/app/devoptions/markstoriescompleted/MarkStoriesCompletedFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/markstoriescompleted/MarkStoriesCompletedFragmentPresenter.kt index 0186fffe056..fcd5d6829c7 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/markstoriescompleted/MarkStoriesCompletedFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/markstoriescompleted/MarkStoriesCompletedFragmentPresenter.kt @@ -11,7 +11,11 @@ import org.oppia.android.app.databinding.databinding.MarkStoriesCompletedStorySu import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.recyclerview.BindableAdapter +import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.devoptions.ModifyLessonProgressController +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [MarkStoriesCompletedFragment]. */ @@ -21,7 +25,8 @@ class MarkStoriesCompletedFragmentPresenter @Inject constructor( private val fragment: Fragment, private val viewModel: MarkStoriesCompletedViewModel, private val modifyLessonProgressController: ModifyLessonProgressController, - private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory + private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) : StorySelector { private lateinit var binding: MarkStoriesCompletedFragmentBinding private lateinit var linearLayoutManager: LinearLayoutManager @@ -95,6 +100,14 @@ class MarkStoriesCompletedFragmentPresenter @Inject constructor( activity.finish() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.markStoriesCompletedToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/devoptions/marktopicscompleted/MarkTopicsCompletedActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/marktopicscompleted/MarkTopicsCompletedActivityPresenter.kt index 890a038c517..9ff455aa79a 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/marktopicscompleted/MarkTopicsCompletedActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/marktopicscompleted/MarkTopicsCompletedActivityPresenter.kt @@ -3,15 +3,22 @@ package org.oppia.android.app.devoptions.marktopicscompleted import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [MarkTopicsCompletedActivity]. */ @ActivityScope class MarkTopicsCompletedActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { fun handleOnCreate(internalProfileId: Int) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp) activity.setContentView(R.layout.mark_topics_completed_activity) diff --git a/app/src/main/java/org/oppia/android/app/devoptions/marktopicscompleted/MarkTopicsCompletedFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/marktopicscompleted/MarkTopicsCompletedFragmentPresenter.kt index bcf6b3d7af6..746888f7414 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/marktopicscompleted/MarkTopicsCompletedFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/marktopicscompleted/MarkTopicsCompletedFragmentPresenter.kt @@ -11,7 +11,11 @@ import org.oppia.android.app.databinding.databinding.MarkTopicsCompletedTopicVie import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.recyclerview.BindableAdapter +import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.devoptions.ModifyLessonProgressController +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [MarkTopicsCompletedFragment]. */ @@ -21,7 +25,8 @@ class MarkTopicsCompletedFragmentPresenter @Inject constructor( private val fragment: Fragment, private val viewModel: MarkTopicsCompletedViewModel, private val modifyLessonProgressController: ModifyLessonProgressController, - private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory + private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) : TopicSelector { private lateinit var binding: MarkTopicsCompletedFragmentBinding private lateinit var linearLayoutManager: LinearLayoutManager @@ -88,6 +93,14 @@ class MarkTopicsCompletedFragmentPresenter @Inject constructor( activity.finish() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.markTopicsCompletedToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserActivityPresenter.kt index fc5a23f71b8..9b1d7aab670 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserActivityPresenter.kt @@ -3,16 +3,23 @@ package org.oppia.android.app.devoptions.mathexpressionparser import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [MathExpressionParserActivity]. */ @ActivityScope class MathExpressionParserActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { /** Called when [MathExpressionParserActivity] is created. Handles UI for the activity. */ fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp) activity.setContentView(R.layout.math_expression_parser_activity) diff --git a/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserFragmentPresenter.kt index 8a309279e8e..4242cadb2fa 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/mathexpressionparser/MathExpressionParserFragmentPresenter.kt @@ -6,13 +6,18 @@ import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import org.oppia.android.app.databinding.databinding.MathExpressionParserFragmentBinding +import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [MathExpressionParserFragment]. */ class MathExpressionParserFragmentPresenter @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, - private val viewModel: MathExpressionParserViewModel + private val viewModel: MathExpressionParserViewModel, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { /** Called when [MathExpressionParserFragment] is created. Handles UI for the fragment. */ fun handleCreateView( @@ -34,6 +39,13 @@ class MathExpressionParserFragmentPresenter @Inject constructor( viewModel = this@MathExpressionParserFragmentPresenter.viewModel } viewModel.initialize(binding.mathExpressionParseResultTextView) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.mathExpressionParserToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } return binding.root } } diff --git a/app/src/main/java/org/oppia/android/app/devoptions/platformparameters/PlatformParametersActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/platformparameters/PlatformParametersActivityPresenter.kt index fdda1abd1e5..5336e900942 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/platformparameters/PlatformParametersActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/platformparameters/PlatformParametersActivityPresenter.kt @@ -3,15 +3,22 @@ package org.oppia.android.app.devoptions.platformparameters import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [PlatformParametersActivity]. */ @ActivityScope class PlatformParametersActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { /** Called when [PlatformParametersActivity] is created. Handles UI for the activity. */ fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp) activity.setContentView(R.layout.platform_parameters_activity) diff --git a/app/src/main/java/org/oppia/android/app/devoptions/platformparameters/PlatformParametersFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/platformparameters/PlatformParametersFragmentPresenter.kt index f27816a0d18..d3f95e83411 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/platformparameters/PlatformParametersFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/platformparameters/PlatformParametersFragmentPresenter.kt @@ -25,13 +25,16 @@ import org.oppia.android.app.model.SyncStatus import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.splash.SplashActivity import org.oppia.android.app.translation.AppLanguageResourceHandler +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.app.view.models.R import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.platformparameter.PlatformParameterControllerDebugImpl import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.platformparameter.EnableEdgeToEdge import javax.inject.Inject import kotlin.system.exitProcess +import org.oppia.android.util.platformparameter.PlatformParameterValue as PlatformParameterConfigValue /** Tag for displaying [AppRestartDialogFragment]. */ const val TAG_PLATFORM_PARAMETER_RESTART_DIALOG = "PLATFORM_PARAMETER_RESTART_DIALOG_TAG" @@ -49,7 +52,9 @@ class PlatformParametersFragmentPresenter @Inject constructor( resourceHandler: AppLanguageResourceHandler, private val oppiaLogger: OppiaLogger, private val platformParameterControllerDebugImpl: PlatformParameterControllerDebugImpl, - private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory + private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterConfigValue ) { private lateinit var binding: PlatformParametersFragmentBinding private lateinit var linearLayoutManager: LinearLayoutManager @@ -107,6 +112,14 @@ class PlatformParametersFragmentPresenter @Inject constructor( } } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.platformParametersToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/devoptions/vieweventlogs/ViewEventLogsActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/vieweventlogs/ViewEventLogsActivityPresenter.kt index 202b36b5479..448c6b6d12f 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/vieweventlogs/ViewEventLogsActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/vieweventlogs/ViewEventLogsActivityPresenter.kt @@ -3,15 +3,22 @@ package org.oppia.android.app.devoptions.vieweventlogs import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [ViewEventLogsActivity]. */ @ActivityScope class ViewEventLogsActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp) activity.setContentView(R.layout.view_event_logs_activity) diff --git a/app/src/main/java/org/oppia/android/app/devoptions/vieweventlogs/ViewEventLogsFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/devoptions/vieweventlogs/ViewEventLogsFragmentPresenter.kt index 76a5fe3928f..2931912de07 100644 --- a/app/src/main/java/org/oppia/android/app/devoptions/vieweventlogs/ViewEventLogsFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/devoptions/vieweventlogs/ViewEventLogsFragmentPresenter.kt @@ -10,6 +10,10 @@ import org.oppia.android.app.databinding.databinding.ViewEventLogsEventLogItemVi import org.oppia.android.app.databinding.databinding.ViewEventLogsFragmentBinding import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.recyclerview.BindableAdapter +import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [ViewEventLogsFragment]. */ @@ -18,7 +22,8 @@ class ViewEventLogsFragmentPresenter @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, private val viewEventLogsViewModel: ViewEventLogsViewModel, - private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory + private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var binding: ViewEventLogsFragmentBinding @@ -52,6 +57,14 @@ class ViewEventLogsFragmentPresenter @Inject constructor( adapter = bindingAdapter } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.viewEventLogsToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerFragmentPresenter.kt index ab42c2e14af..7bcb0eff6c6 100644 --- a/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerFragmentPresenter.kt @@ -4,6 +4,7 @@ import android.view.LayoutInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup +import android.widget.LinearLayout import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar @@ -33,11 +34,13 @@ import org.oppia.android.app.options.OptionsActivity import org.oppia.android.app.profileprogress.ProfileProgressActivity import org.oppia.android.app.topic.TopicActivity import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.domain.topic.TopicController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.platformparameter.EnableEdgeToEdge import org.oppia.android.util.platformparameter.EnableMultipleClassrooms import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.CurrentUserProfileIdIntentDecorator.extractCurrentUserProfileId @@ -59,6 +62,7 @@ class NavigationDrawerFragmentPresenter @Inject constructor( private val footerViewModel: NavigationDrawerFooterViewModel, private val developerOptionsStarter: Optional, @EnableMultipleClassrooms private val enableMultipleClassrooms: PlatformParameterValue, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue, ) : NavigationView.OnNavigationItemSelectedListener { private lateinit var drawerToggle: ActionBarDrawerToggle private lateinit var drawerLayout: DrawerLayout @@ -94,6 +98,16 @@ class NavigationDrawerFragmentPresenter @Inject constructor( // TODO(#3382): Remove debug only code from prod build (also check imports, constructor and drawer_fragment.xml) setIfDeveloperOptionsMenuItemListener() + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToNavigationDrawer( + activity = activity, + drawerRoot = binding.root, + drawerContentLayout = binding.drawerNestedScrollView.getChildAt(0) as LinearLayout, + navigationView = binding.fragmentDrawerNavView, + statusBarColorRes = R.color.component_color_shared_slide_drawer_open_status_bar_color + ) + } + return binding.root } @@ -410,11 +424,13 @@ class NavigationDrawerFragmentPresenter @Inject constructor( override fun onDrawerOpened(drawerView: View) { super.onDrawerOpened(drawerView) fragment.requireActivity().invalidateOptionsMenu() - StatusBarColor.statusBarColorUpdate( - R.color.component_color_shared_slide_drawer_open_status_bar_color, - activity, - false - ) + if (!enableEdgeToEdge.value) { + StatusBarColor.statusBarColorUpdate( + R.color.component_color_shared_slide_drawer_open_status_bar_color, + activity, + false + ) + } } override fun onDrawerClosed(drawerView: View) { @@ -422,11 +438,13 @@ class NavigationDrawerFragmentPresenter @Inject constructor( // It's possible in some rare cases for the activity to be gone while the drawer is // closing (possibly an out-of-lifecycle call from the AndroidX component). fragment.activity?.invalidateOptionsMenu() - StatusBarColor.statusBarColorUpdate( - R.color.component_color_shared_activity_status_bar_color, - activity, - false - ) + if (!enableEdgeToEdge.value) { + StatusBarColor.statusBarColorUpdate( + R.color.component_color_shared_activity_status_bar_color, + activity, + false + ) + } } } drawerLayout.addDrawerListener(drawerToggle) @@ -449,21 +467,25 @@ class NavigationDrawerFragmentPresenter @Inject constructor( override fun onDrawerOpened(drawerView: View) { super.onDrawerOpened(drawerView) fragment.requireActivity().invalidateOptionsMenu() - StatusBarColor.statusBarColorUpdate( - R.color.component_color_shared_slide_drawer_open_status_bar_color, - activity, - false - ) + if (!enableEdgeToEdge.value) { + StatusBarColor.statusBarColorUpdate( + R.color.component_color_shared_slide_drawer_open_status_bar_color, + activity, + false + ) + } } override fun onDrawerClosed(drawerView: View) { super.onDrawerClosed(drawerView) fragment.requireActivity().invalidateOptionsMenu() - StatusBarColor.statusBarColorUpdate( - R.color.component_color_shared_activity_status_bar_color, - activity, - false - ) + if (!enableEdgeToEdge.value) { + StatusBarColor.statusBarColorUpdate( + R.color.component_color_shared_activity_status_bar_color, + activity, + false + ) + } } } drawerLayout.addDrawerListener(drawerToggle) diff --git a/app/src/main/java/org/oppia/android/app/help/HelpActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/help/HelpActivityPresenter.kt index 6428ada3b35..693648d9a15 100644 --- a/app/src/main/java/org/oppia/android/app/help/HelpActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/help/HelpActivityPresenter.kt @@ -23,14 +23,18 @@ import org.oppia.android.app.model.PolicyPage import org.oppia.android.app.policies.PoliciesFragment import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.util.extensions.putProto +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [HelpActivity]. */ @ActivityScope class HelpActivityPresenter @Inject constructor( private val activity: AppCompatActivity, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var navigationDrawerFragment: NavigationDrawerFragment private lateinit var toolbar: Toolbar @@ -57,6 +61,10 @@ class HelpActivityPresenter @Inject constructor( internalPolicyPage = policiesActivityParams.policyPage } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } + if (isFromNavigationDrawer) { activity.setContentView(R.layout.help_activity) setUpToolbar() @@ -69,6 +77,14 @@ class HelpActivityPresenter @Inject constructor( activity.finish() } } + + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToToolbarContainer( + activity, + toolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } val titleTextView = activity.findViewById(R.id.options_activity_selected_options_title) if (titleTextView != null) { diff --git a/app/src/main/java/org/oppia/android/app/help/faq/FAQListActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/help/faq/FAQListActivityPresenter.kt index 19f0f43056f..1abda3bc8e0 100644 --- a/app/src/main/java/org/oppia/android/app/help/faq/FAQListActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/help/faq/FAQListActivityPresenter.kt @@ -7,17 +7,24 @@ import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.databinding.databinding.FaqListActivityBinding import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [FAQListActivity]. */ @ActivityScope class FAQListActivityPresenter @Inject constructor( private val activity: AppCompatActivity, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var faqListActivityToolbar: Toolbar fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding = DataBindingUtil.setContentView(activity, R.layout.faq_list_activity) binding.apply { @@ -34,6 +41,14 @@ class FAQListActivityPresenter @Inject constructor( (activity as FAQListActivity).finish() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + faqListActivityToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + if (getFAQListFragment() == null) { activity.supportFragmentManager.beginTransaction().add( R.id.faq_list_fragment_placeholder, diff --git a/app/src/main/java/org/oppia/android/app/help/faq/faqsingle/FAQSingleActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/help/faq/faqsingle/FAQSingleActivityPresenter.kt index 74087fcd225..e377f05ddbf 100644 --- a/app/src/main/java/org/oppia/android/app/help/faq/faqsingle/FAQSingleActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/help/faq/faqsingle/FAQSingleActivityPresenter.kt @@ -8,8 +8,11 @@ import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.databinding.databinding.FaqSingleActivityBinding import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.util.gcsresource.DefaultResourceBucketName import org.oppia.android.util.parser.html.HtmlParser +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [FAQSingleActivity]. */ @@ -18,12 +21,17 @@ class FAQSingleActivityPresenter @Inject constructor( private val activity: AppCompatActivity, private val htmlParserFactory: HtmlParser.Factory, @DefaultResourceBucketName private val resourceBucketName: String, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var faqSingleActivityToolbar: Toolbar fun handleOnCreate(question: String, answer: String) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding = DataBindingUtil.setContentView( activity, R.layout.faq_single_activity @@ -41,6 +49,13 @@ class FAQSingleActivityPresenter @Inject constructor( binding.faqSingleActivityToolbar.setNavigationOnClickListener { (activity as FAQSingleActivity).finish() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + faqSingleActivityToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } activity.findViewById(R.id.faq_question_text_view).text = question // NOTE: Here entityType and entityId can be anything as it will actually not get used. diff --git a/app/src/main/java/org/oppia/android/app/help/thirdparty/LicenseListActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/help/thirdparty/LicenseListActivityPresenter.kt index 203da25e090..5756829f77d 100644 --- a/app/src/main/java/org/oppia/android/app/help/thirdparty/LicenseListActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/help/thirdparty/LicenseListActivityPresenter.kt @@ -6,17 +6,25 @@ import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.databinding.databinding.LicenseListActivityBinding import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [LicenseListActivity]. */ @ActivityScope class LicenseListActivityPresenter @Inject constructor( private val activity: AppCompatActivity, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { /** Handles onCreate() method of the [LicenseListActivity]. */ fun handleOnCreate(dependencyIndex: Int, isMultipane: Boolean) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding = DataBindingUtil.setContentView( activity, @@ -36,6 +44,13 @@ class LicenseListActivityPresenter @Inject constructor( binding.licenseListActivityToolbar.setNavigationOnClickListener { (activity as LicenseListActivity).finish() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + licenseListActivityToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } if (getLicenseListFragment() == null) { val licenseListFragment = LicenseListFragment.newInstance(dependencyIndex, isMultipane) activity.supportFragmentManager.beginTransaction() diff --git a/app/src/main/java/org/oppia/android/app/help/thirdparty/LicenseTextViewerActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/help/thirdparty/LicenseTextViewerActivityPresenter.kt index 2148cfcc9a7..d56ba8c2bec 100644 --- a/app/src/main/java/org/oppia/android/app/help/thirdparty/LicenseTextViewerActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/help/thirdparty/LicenseTextViewerActivityPresenter.kt @@ -6,19 +6,27 @@ import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.databinding.databinding.LicenseTextViewerActivityBinding import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.util.accessibility.AccessibilityService +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [LicenseTextViewerActivity]. */ @ActivityScope class LicenseTextViewerActivityPresenter @Inject constructor( private val activity: AppCompatActivity, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { @Inject lateinit var accessibilityService: AccessibilityService /** Handles onCreate() method of the [LicenseTextViewerActivity]. */ fun handleOnCreate(dependencyIndex: Int, licenseIndex: Int) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding = DataBindingUtil.setContentView( activity, @@ -45,6 +53,13 @@ class LicenseTextViewerActivityPresenter @Inject constructor( binding.licenseTextViewerActivityToolbar.setNavigationOnClickListener { (activity as LicenseTextViewerActivity).finish() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + licenseTextViewerActivityToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } if (!accessibilityService.isScreenReaderEnabled()) { binding.licenseTextViewerActivityToolbarTitle.setOnClickListener { diff --git a/app/src/main/java/org/oppia/android/app/help/thirdparty/ThirdPartyDependencyListActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/help/thirdparty/ThirdPartyDependencyListActivityPresenter.kt index 38605a1c859..50853c49355 100644 --- a/app/src/main/java/org/oppia/android/app/help/thirdparty/ThirdPartyDependencyListActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/help/thirdparty/ThirdPartyDependencyListActivityPresenter.kt @@ -6,17 +6,25 @@ import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.databinding.databinding.ThirdPartyDependencyListActivityBinding import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [ThirdPartyDependencyListActivity]. */ @ActivityScope class ThirdPartyDependencyListActivityPresenter @Inject constructor( private val activity: AppCompatActivity, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { /** Handles onCreate() method of the [ThirdPartyDependencyListActivity]. */ fun handleOnCreate(isMultipane: Boolean) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding = DataBindingUtil.setContentView( activity, @@ -37,6 +45,13 @@ class ThirdPartyDependencyListActivityPresenter @Inject constructor( binding.thirdPartyDependencyListActivityToolbar.setNavigationOnClickListener { (activity as ThirdPartyDependencyListActivity).finish() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + thirdPartyDependencyListActivityToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } if (getThirdPartyDependencyListFragment() == null) { val thirdPartyDependencyListFragment = diff --git a/app/src/main/java/org/oppia/android/app/home/HomeActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/home/HomeActivityPresenter.kt index 98455074306..4cbabb4dbed 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeActivityPresenter.kt @@ -9,18 +9,35 @@ import org.oppia.android.app.drawer.NavigationDrawerFragment import org.oppia.android.app.spotlight.SpotlightFragment import org.oppia.android.app.spotlight.SpotlightManager import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject const val TAG_HOME_FRAGMENT = "HOME_FRAGMENT" /** The presenter for [HomeActivity]. */ @ActivityScope -class HomeActivityPresenter @Inject constructor(private val activity: AppCompatActivity) { +class HomeActivityPresenter @Inject constructor( + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue +) { private var navigationDrawerFragment: NavigationDrawerFragment? = null fun handleOnCreate(internalProfileId: Int) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.home_activity) setUpNavigationDrawer() + if (enableEdgeToEdge.value) { + val toolbar = activity.findViewById(R.id.home_activity_toolbar) + EdgeToEdgeHelper.applyToToolbarContainer( + activity, + toolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } if (getHomeFragment() == null) { activity.supportFragmentManager.beginTransaction().add( R.id.home_fragment_placeholder, diff --git a/app/src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedActivityPresenter.kt index b99d5d0e33e..13ee8cd48f8 100644 --- a/app/src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedActivityPresenter.kt @@ -8,18 +8,26 @@ import org.oppia.android.app.model.RecentlyPlayedActivityParams import org.oppia.android.app.model.RecentlyPlayedActivityTitle import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [RecentlyPlayedActivity]. */ @ActivityScope class RecentlyPlayedActivityPresenter @Inject constructor( private val activity: AppCompatActivity, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { fun handleOnCreate(recentlyPlayedActivityParams: RecentlyPlayedActivityParams) { activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp) activity.title = getTitle(recentlyPlayedActivityParams) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding = DataBindingUtil.setContentView( activity, R.layout.recently_played_activity @@ -29,6 +37,15 @@ class RecentlyPlayedActivityPresenter @Inject constructor( (activity as RecentlyPlayedActivity).finish() } binding.recentlyPlayedToolbar.title = getTitle(recentlyPlayedActivityParams) + + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.recentlyPlayedToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + if (getRecentlyPlayedFragment() == null) { activity.supportFragmentManager.beginTransaction().add( R.id.recently_played_fragment_placeholder, diff --git a/app/src/main/java/org/oppia/android/app/mydownloads/MyDownloadsActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/mydownloads/MyDownloadsActivityPresenter.kt index c8657e88092..862cd8edf31 100644 --- a/app/src/main/java/org/oppia/android/app/mydownloads/MyDownloadsActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/mydownloads/MyDownloadsActivityPresenter.kt @@ -3,12 +3,21 @@ package org.oppia.android.app.mydownloads import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [MyDownloadsActivity]. */ @ActivityScope -class MyDownloadsActivityPresenter @Inject constructor(private val activity: AppCompatActivity) { +class MyDownloadsActivityPresenter @Inject constructor( + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue +) { fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.my_downloads_activity) if (getMyDownloadsFragment() == null) { activity.supportFragmentManager.beginTransaction().add( diff --git a/app/src/main/java/org/oppia/android/app/mydownloads/MyDownloadsFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/mydownloads/MyDownloadsFragmentPresenter.kt index b8e0fa47f31..37d2709d74b 100644 --- a/app/src/main/java/org/oppia/android/app/mydownloads/MyDownloadsFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/mydownloads/MyDownloadsFragmentPresenter.kt @@ -3,6 +3,7 @@ package org.oppia.android.app.mydownloads import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.tabs.TabLayout @@ -11,13 +12,18 @@ import org.oppia.android.app.databinding.databinding.MyDownloadsFragmentBinding import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [MyDownloadsFragment]. */ @FragmentScope class MyDownloadsFragmentPresenter @Inject constructor( + private val activity: AppCompatActivity, private val fragment: Fragment, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? { val binding = MyDownloadsFragmentBinding.inflate( @@ -37,6 +43,13 @@ class MyDownloadsFragmentPresenter @Inject constructor( R.id.my_downloads_tabs_viewpager ) as ViewPager2 setUpViewPager(tabLayout, viewPager) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.myDownloadsToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/onboarding/OnboardingActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/onboarding/OnboardingActivityPresenter.kt index db4baea145e..6f4389186fe 100644 --- a/app/src/main/java/org/oppia/android/app/onboarding/OnboardingActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/onboarding/OnboardingActivityPresenter.kt @@ -3,12 +3,22 @@ package org.oppia.android.app.onboarding import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [OnboardingActivity]. */ @ActivityScope -class OnboardingActivityPresenter @Inject constructor(private val activity: AppCompatActivity) { +class OnboardingActivityPresenter @Inject constructor( + private val activity: AppCompatActivity, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue +) { fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.onboarding_activity) if (getOnboardingFragment() == null) { activity.supportFragmentManager.beginTransaction().add( diff --git a/app/src/main/java/org/oppia/android/app/onboarding/OnboardingFragmentPresenterV1.kt b/app/src/main/java/org/oppia/android/app/onboarding/OnboardingFragmentPresenterV1.kt index 9ec394a348b..efe02d53b9f 100644 --- a/app/src/main/java/org/oppia/android/app/onboarding/OnboardingFragmentPresenterV1.kt +++ b/app/src/main/java/org/oppia/android/app/onboarding/OnboardingFragmentPresenterV1.kt @@ -6,6 +6,8 @@ import android.view.ViewGroup import android.widget.ImageView import android.widget.LinearLayout import androidx.appcompat.app.AppCompatActivity +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.viewpager2.widget.ViewPager2 import org.oppia.android.app.databinding.databinding.OnboardingFragmentBinding @@ -17,8 +19,11 @@ import org.oppia.android.app.policies.RouteToPoliciesListener import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.util.parser.html.HtmlParser import org.oppia.android.util.parser.html.PolicyType +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.statusbar.StatusBarColor import javax.inject.Inject @@ -31,10 +36,13 @@ class OnboardingFragmentPresenterV1 @Inject constructor( private val onboardingSlideFinalViewModel: OnboardingSlideFinalViewModel, private val resourceHandler: AppLanguageResourceHandler, private val htmlParserFactory: HtmlParser.Factory, - private val multiTypeBuilderFactory: BindableAdapter.MultiTypeBuilder.Factory + private val multiTypeBuilderFactory: BindableAdapter.MultiTypeBuilder.Factory, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) : OnboardingNavigationListener, HtmlParser.PolicyOppiaTagActionListener { private val dotsList = ArrayList() private lateinit var binding: OnboardingFragmentBinding + private var statusBarSpacer: View? = null fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View { binding = OnboardingFragmentBinding.inflate( @@ -49,6 +57,13 @@ class OnboardingFragmentPresenterV1 @Inject constructor( it.presenter = this it.viewModel = onboardingViewModel } + if (enableEdgeToEdge.value) { + statusBarSpacer = EdgeToEdgeHelper.applyToRootConstraintLayout( + activity, + binding.root as ConstraintLayout, + R.color.component_color_onboarding_1_status_bar_color + ) + } setUpViewPager() addDots() return binding.root @@ -156,32 +171,17 @@ class OnboardingFragmentPresenterV1 @Inject constructor( } private fun onboardingStatusBarColorUpdate(position: Int) { - when (position) { - 0 -> StatusBarColor.statusBarColorUpdate( - R.color.component_color_onboarding_1_status_bar_color, - activity, - false - ) - 1 -> StatusBarColor.statusBarColorUpdate( - R.color.component_color_onboarding_2_status_bar_color, - activity, - false - ) - 2 -> StatusBarColor.statusBarColorUpdate( - R.color.component_color_onboarding_3_status_bar_color, - activity, - false - ) - 3 -> StatusBarColor.statusBarColorUpdate( - R.color.component_color_onboarding_4_status_bar_color, - activity, - false - ) - else -> StatusBarColor.statusBarColorUpdate( - R.color.component_color_shared_activity_status_bar_color, - activity, - false - ) + val colorRes = when (position) { + 0 -> R.color.component_color_onboarding_1_status_bar_color + 1 -> R.color.component_color_onboarding_2_status_bar_color + 2 -> R.color.component_color_onboarding_3_status_bar_color + 3 -> R.color.component_color_onboarding_4_status_bar_color + else -> R.color.component_color_shared_activity_status_bar_color + } + if (enableEdgeToEdge.value) { + statusBarSpacer?.setBackgroundColor(ContextCompat.getColor(activity, colorRes)) + } else { + StatusBarColor.statusBarColorUpdate(colorRes, activity, false) } } diff --git a/app/src/main/java/org/oppia/android/app/ongoingtopiclist/OngoingTopicListActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/ongoingtopiclist/OngoingTopicListActivityPresenter.kt index 2bbbd5267ab..395a0d9d9e0 100644 --- a/app/src/main/java/org/oppia/android/app/ongoingtopiclist/OngoingTopicListActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/ongoingtopiclist/OngoingTopicListActivityPresenter.kt @@ -3,14 +3,21 @@ package org.oppia.android.app.ongoingtopiclist import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [OngoingTopicListActivity]. */ @ActivityScope class OngoingTopicListActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { fun handleOnCreate(internalProfileId: Int) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.ongoing_topic_list_activity) if (getOngoingTopicListFragment() == null) { activity.supportFragmentManager.beginTransaction().add( diff --git a/app/src/main/java/org/oppia/android/app/ongoingtopiclist/OngoingTopicListFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/ongoingtopiclist/OngoingTopicListFragmentPresenter.kt index 2d1ef6694a8..250f972acf8 100644 --- a/app/src/main/java/org/oppia/android/app/ongoingtopiclist/OngoingTopicListFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/ongoingtopiclist/OngoingTopicListFragmentPresenter.kt @@ -10,6 +10,9 @@ import org.oppia.android.app.databinding.databinding.OngoingTopicItemBinding import org.oppia.android.app.databinding.databinding.OngoingTopicListFragmentBinding import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [OngoingTopicListFragment]. */ @@ -17,7 +20,8 @@ class OngoingTopicListFragmentPresenter @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, private val ongoingTopicListViewModel: OngoingTopicListViewModel, - private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory + private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var binding: OngoingTopicListFragmentBinding @@ -51,6 +55,14 @@ class OngoingTopicListFragmentPresenter @Inject constructor( it.lifecycleOwner = fragment it.viewModel = ongoingTopicListViewModel } + + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.ongoingTopicListToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/options/AppLanguageActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/options/AppLanguageActivityPresenter.kt index 8c166b4aeb2..c3669de78a8 100644 --- a/app/src/main/java/org/oppia/android/app/options/AppLanguageActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/options/AppLanguageActivityPresenter.kt @@ -6,20 +6,37 @@ import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.databinding.databinding.AppLanguageActivityBinding import org.oppia.android.app.model.OppiaLanguage import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [AppLanguageActivity]. */ @ActivityScope -class AppLanguageActivityPresenter @Inject constructor(private val activity: AppCompatActivity) { +class AppLanguageActivityPresenter @Inject constructor( + private val activity: AppCompatActivity, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue +) { private lateinit var oppiaLanguage: OppiaLanguage /** Initializes and creates the views for [AppLanguageActivity]. */ fun handleOnCreate(oppiaLanguage: OppiaLanguage, profileId: Int) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding: AppLanguageActivityBinding = DataBindingUtil.setContentView( activity, R.layout.app_language_activity, ) binding.appLanguageToolbar.setNavigationOnClickListener { activity.finish() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.appLanguageToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } setLanguageSelected(oppiaLanguage) if (getAppLanguageFragment() == null) { val appLanguageFragment = AppLanguageFragment.newInstance(oppiaLanguage, profileId) diff --git a/app/src/main/java/org/oppia/android/app/options/AudioLanguageActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/options/AudioLanguageActivityPresenter.kt index d262d1d660a..ea17efc0b4d 100644 --- a/app/src/main/java/org/oppia/android/app/options/AudioLanguageActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/options/AudioLanguageActivityPresenter.kt @@ -11,12 +11,19 @@ import org.oppia.android.app.model.AudioLanguageActivityParams import org.oppia.android.app.model.AudioLanguageActivityResultBundle import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.util.extensions.putProtoExtra +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [AudioLanguageActivity]. */ @ActivityScope -class AudioLanguageActivityPresenter @Inject constructor(private val activity: AppCompatActivity) { +class AudioLanguageActivityPresenter @Inject constructor( + private val activity: AppCompatActivity, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue +) { private lateinit var audioLanguage: AudioLanguage /** Handles when the activity is first created. */ @@ -27,6 +34,9 @@ class AudioLanguageActivityPresenter @Inject constructor(private val activity: A ) { this.audioLanguage = audioLanguage + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding: AudioLanguageActivityBinding = DataBindingUtil.setContentView(activity, R.layout.audio_language_activity) activity.setSupportActionBar(binding.audioLanguageToolbar) @@ -36,6 +46,14 @@ class AudioLanguageActivityPresenter @Inject constructor(private val activity: A finishWithResult() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.audioLanguageToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + if (getAudioLanguageFragment() == null) { val audioLanguageFragment = AudioLanguageFragment.newInstance( audioLanguage, diff --git a/app/src/main/java/org/oppia/android/app/options/OptionsActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/options/OptionsActivityPresenter.kt index cbd6515d5a9..7cca2947904 100644 --- a/app/src/main/java/org/oppia/android/app/options/OptionsActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/options/OptionsActivityPresenter.kt @@ -14,12 +14,16 @@ import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.model.OppiaLanguage import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [OptionsActivity]. */ @ActivityScope class OptionsActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private var navigationDrawerFragment: NavigationDrawerFragment? = null private lateinit var toolbar: Toolbar @@ -33,6 +37,9 @@ class OptionsActivityPresenter @Inject constructor( selectedFragment: String, profileId: Int ) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } if (isFromNavigationDrawer) { activity.setContentView(R.layout.option_activity) setUpToolbar() @@ -45,6 +52,13 @@ class OptionsActivityPresenter @Inject constructor( activity.finish() } } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToToolbarContainer( + activity, + toolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } val titleTextView = activity.findViewById(R.id.options_activity_selected_options_title) if (titleTextView != null) { diff --git a/app/src/main/java/org/oppia/android/app/options/ReadingTextSizeActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/options/ReadingTextSizeActivityPresenter.kt index 3b50a987ef2..b50b89a8d01 100644 --- a/app/src/main/java/org/oppia/android/app/options/ReadingTextSizeActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/options/ReadingTextSizeActivityPresenter.kt @@ -5,18 +5,33 @@ import androidx.appcompat.widget.Toolbar import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [ReadingTextSizeActivity]. */ @ActivityScope class ReadingTextSizeActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var fontSize: ReadingTextSize fun handleOnCreate(preferredTextSize: ReadingTextSize) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.reading_text_size_activity) - setToolbar() + val toolbar = setToolbar() + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + toolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } fontSize = preferredTextSize if (getReadingTextSizeFragment() == null) { val readingTextSizeFragment = ReadingTextSizeFragment.newInstance(preferredTextSize) @@ -25,11 +40,12 @@ class ReadingTextSizeActivityPresenter @Inject constructor( } } - private fun setToolbar() { + private fun setToolbar(): Toolbar { val readingTextSizeToolbar: Toolbar = activity.findViewById(R.id.reading_text_size_toolbar) readingTextSizeToolbar.setNavigationOnClickListener { activity.onBackPressedDispatcher.onBackPressed() } + return readingTextSizeToolbar } fun setSelectedReadingTextSize(fontSize: ReadingTextSize) { diff --git a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivityPresenter.kt index 2f11fa4580b..8b63b2b3f10 100644 --- a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivityPresenter.kt @@ -34,6 +34,7 @@ import org.oppia.android.app.topic.TopicActivity import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R import org.oppia.android.app.utility.FontScaleConfigurationUtil +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.exploration.ExplorationDataController import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.oppialogger.analytics.LearnerAnalyticsLogger @@ -42,6 +43,8 @@ import org.oppia.android.domain.translation.TranslationController import org.oppia.android.util.accessibility.AccessibilityService import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject private const val TAG_UNSAVED_EXPLORATION_DIALOG = "UNSAVED_EXPLORATION_DIALOG" @@ -62,7 +65,9 @@ class ExplorationActivityPresenter @Inject constructor( private val oppiaLogger: OppiaLogger, private val learnerAnalyticsLogger: LearnerAnalyticsLogger, private val resourceHandler: AppLanguageResourceHandler, - private val surveyGatingController: SurveyGatingController + private val surveyGatingController: SurveyGatingController, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { @Inject lateinit var accessibilityService: AccessibilityService @@ -93,6 +98,9 @@ class ExplorationActivityPresenter @Inject constructor( parentScreen: ExplorationActivityParams.ParentScreen, isCheckpointingEnabled: Boolean ) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } binding = DataBindingUtil.setContentView( activity, R.layout.exploration_activity @@ -105,6 +113,13 @@ class ExplorationActivityPresenter @Inject constructor( explorationToolbar = binding.explorationToolbar explorationToolbarTitle = binding.explorationToolbarTitle activity.setSupportActionBar(explorationToolbar) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + explorationToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } if (!accessibilityService.isScreenReaderEnabled()) { binding.explorationToolbarTitle.setOnClickListener { diff --git a/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt index e66eb76794f..1caca83a60d 100755 --- a/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt @@ -55,6 +55,8 @@ import org.oppia.android.util.data.DataProvider import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.gcsresource.DefaultResourceBucketName import org.oppia.android.util.parser.html.ExplorationHtmlParserEntityType +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.system.OppiaClock import javax.inject.Inject @@ -84,7 +86,8 @@ class StateFragmentPresenter @Inject constructor( private val stateViewModel: StateViewModel, private val accessibilityService: AccessibilityService, private val resourceHandler: AppLanguageResourceHandler, - private val surveyGatingController: SurveyGatingController + private val surveyGatingController: SurveyGatingController, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private val routeToHintsAndSolutionListener = activity as RouteToHintsAndSolutionListener @@ -128,6 +131,12 @@ class StateFragmentPresenter @Inject constructor( container, /* attachToRoot= */ false ) + if (enableEdgeToEdge.value) { + // The activity's EdgeToEdgeHelper applies the status-bar inset to the AppBarLayout; the + // legacy fitsSystemWindows on this fragment's root would re-apply the same inset as inner + // top padding, leaving a blank gap below the toolbar. + binding.root.fitsSystemWindows = false + } recyclerViewAssembler = createRecyclerViewAssembler( assemblerBuilderFactory.create(resourceBucketName, entityType, profileId, userAnswerState), binding.congratulationsTextView, diff --git a/app/src/main/java/org/oppia/android/app/policies/PoliciesActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/policies/PoliciesActivityPresenter.kt index 74e6b999a52..4261607178d 100644 --- a/app/src/main/java/org/oppia/android/app/policies/PoliciesActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/policies/PoliciesActivityPresenter.kt @@ -8,16 +8,23 @@ import org.oppia.android.app.model.PoliciesFragmentArguments import org.oppia.android.app.model.PolicyPage import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [PoliciesActivity]. */ class PoliciesActivityPresenter @Inject constructor( private val activity: AppCompatActivity, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { /** Handles onCreate() method of the [PoliciesActivity]. */ fun handleOnCreate(policiesActivityParams: PoliciesActivityParams) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.policies_activity) val toolbar = setUpToolbar(policiesActivityParams.policyPage) activity.supportActionBar!!.setDisplayHomeAsUpEnabled(true) @@ -26,6 +33,14 @@ class PoliciesActivityPresenter @Inject constructor( activity.finish() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + toolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + if (getPoliciesFragment() == null) { val policiesFragmentArguments = PoliciesFragmentArguments diff --git a/app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt index 7cfbd1abf60..78dd938a2d6 100644 --- a/app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt @@ -29,11 +29,13 @@ import org.oppia.android.app.profile.AddProfileActivity.Companion.ADD_PROFILE_AC import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R import org.oppia.android.app.utility.TextInputEditTextHelper.Companion.onTextChanged +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.extensions.getProtoExtra import org.oppia.android.util.platformparameter.EnableDownloadsSupport +import org.oppia.android.util.platformparameter.EnableEdgeToEdge import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject @@ -44,7 +46,10 @@ class AddProfileActivityPresenter @Inject constructor( private val profileManagementController: ProfileManagementController, private val resourceHandler: AppLanguageResourceHandler, private val profileViewModel: AddProfileViewModel, - @EnableDownloadsSupport private val enableDownloadsSupport: PlatformParameterValue + @EnableDownloadsSupport + private val enableDownloadsSupport: PlatformParameterValue, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var uploadImageView: ImageView private var selectedImage: Uri? = null @@ -60,6 +65,9 @@ class AddProfileActivityPresenter @Inject constructor( lateinit var resultLauncher: ActivityResultLauncher fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding = DataBindingUtil.setContentView( activity, R.layout.add_profile_activity @@ -91,6 +99,14 @@ class AddProfileActivityPresenter @Inject constructor( activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp) activity.supportActionBar?.setHomeActionContentDescription(R.string.admin_auth_close) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToToolbarContainer( + activity, + toolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + uploadImageView = binding.addProfileActivityUserImageView Glide.with(activity) .load(R.drawable.ic_default_avatar) diff --git a/app/src/main/java/org/oppia/android/app/profile/AdminAuthActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/profile/AdminAuthActivityPresenter.kt index 1fbe81a69a7..7bd3ef15c40 100644 --- a/app/src/main/java/org/oppia/android/app/profile/AdminAuthActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/profile/AdminAuthActivityPresenter.kt @@ -13,10 +13,13 @@ import org.oppia.android.app.profile.AdminAuthActivity.Companion.ADMIN_AUTH_ACTI import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R import org.oppia.android.app.utility.TextInputEditTextHelper.Companion.onTextChanged +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.extensions.getProtoExtra +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.CurrentUserProfileIdIntentDecorator.extractCurrentUserProfileId import org.oppia.android.util.profile.toProfileIdPreservingZero import javax.inject.Inject @@ -29,6 +32,8 @@ class AdminAuthActivityPresenter @Inject constructor( private val authViewModel: AdminAuthViewModel, private val resourceHandler: AppLanguageResourceHandler, private val profileManagementController: ProfileManagementController, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var binding: AdminAuthActivityBinding private val args by lazy { @@ -40,6 +45,9 @@ class AdminAuthActivityPresenter @Inject constructor( /** Binds ViewModel and sets up text and button listeners. */ fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } binding = DataBindingUtil.setContentView( activity, R.layout.admin_auth_activity @@ -47,6 +55,15 @@ class AdminAuthActivityPresenter @Inject constructor( binding.adminAuthToolbar.setNavigationOnClickListener { (activity as AdminAuthActivity).finish() } + + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.adminAuthToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + val adminPin = checkNotNull(args?.adminPin) { "Expected AdminAuthActivity.admin_auth_admin_pin to be in intent extras." } diff --git a/app/src/main/java/org/oppia/android/app/profile/AdminPinActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/profile/AdminPinActivityPresenter.kt index 97cee6979ac..96d7a97acc6 100644 --- a/app/src/main/java/org/oppia/android/app/profile/AdminPinActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/profile/AdminPinActivityPresenter.kt @@ -15,11 +15,14 @@ import org.oppia.android.app.profile.AdminPinActivity.Companion.ADMIN_PIN_ACTIVI import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R import org.oppia.android.app.utility.TextInputEditTextHelper.Companion.onTextChanged +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.extensions.getProtoExtra import org.oppia.android.util.parser.html.HtmlParser +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.toProfileIdPreservingZero import javax.inject.Inject @@ -31,7 +34,9 @@ class AdminPinActivityPresenter @Inject constructor( private val profileManagementController: ProfileManagementController, private val adminViewModel: AdminPinViewModel, private val resourceHandler: AppLanguageResourceHandler, - private val htmlParserFactory: HtmlParser.Factory + private val htmlParserFactory: HtmlParser.Factory, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { private val args by lazy { activity.intent.getProtoExtra( @@ -42,10 +47,20 @@ class AdminPinActivityPresenter @Inject constructor( /** Binds ViewModel and sets up text and button listeners. */ fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding = DataBindingUtil.setContentView(activity, R.layout.admin_pin_activity) activity.setSupportActionBar(binding.adminPinToolbar) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToToolbarContainer( + activity, + binding.adminPinToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp) activity.supportActionBar?.setHomeActionContentDescription(R.string.admin_auth_close) diff --git a/app/src/main/java/org/oppia/android/app/profile/PinPasswordActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/profile/PinPasswordActivityPresenter.kt index 99f1d8f0a3a..8281157e013 100644 --- a/app/src/main/java/org/oppia/android/app/profile/PinPasswordActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/profile/PinPasswordActivityPresenter.kt @@ -18,12 +18,14 @@ import org.oppia.android.app.profile.PinPasswordActivity.Companion.PIN_PASSWORD_ import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R import org.oppia.android.app.utility.TextInputEditTextHelper.Companion.onTextChanged +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.app.utility.lifecycle.LifecycleSafeTimerFactory import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.util.accessibility.AccessibilityService import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.extensions.getProtoExtra +import org.oppia.android.util.platformparameter.EnableEdgeToEdge import org.oppia.android.util.platformparameter.EnableMultipleClassrooms import org.oppia.android.util.platformparameter.EnableOnboardingFlowV2 import org.oppia.android.util.platformparameter.PlatformParameterValue @@ -43,7 +45,8 @@ class PinPasswordActivityPresenter @Inject constructor( private val resourceHandler: AppLanguageResourceHandler, private val accessibilityService: AccessibilityService, @EnableMultipleClassrooms private val enableMultipleClassrooms: PlatformParameterValue, - @EnableOnboardingFlowV2 private val enableOnboardingFlowV2: PlatformParameterValue + @EnableOnboardingFlowV2 private val enableOnboardingFlowV2: PlatformParameterValue, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private var internalProfileId = -1 private var profileId = LegacyProfileId.getDefaultInstance() @@ -60,6 +63,9 @@ class PinPasswordActivityPresenter @Inject constructor( internalProfileId = args?.internalProfileId ?: -1 profileId = LegacyProfileId.newBuilder().setInternalId(internalProfileId).build() + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding = DataBindingUtil.setContentView( activity, R.layout.pin_password_activity @@ -75,6 +81,14 @@ class PinPasswordActivityPresenter @Inject constructor( (activity as PinPasswordActivity).finish() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.pinPasswordToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + binding.showPin.setOnClickListener { pinViewModel.showPassword.set(!pinViewModel.showPassword.get()!!) if (!pinViewModel.showPassword.get()!!) { diff --git a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserActivityPresenter.kt index 24a3770fbd5..78b7031dedc 100644 --- a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserActivityPresenter.kt @@ -8,8 +8,10 @@ import org.oppia.android.app.model.ProfileChooserActivityParams.ParentScreen import org.oppia.android.app.model.ProfileChooserFragmentArguments import org.oppia.android.app.testing.ProfileChooserFragmentTestActivity import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.util.extensions.putProto +import org.oppia.android.util.platformparameter.EnableEdgeToEdge import org.oppia.android.util.platformparameter.EnableOnboardingFlowV2 import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.CurrentUserProfileIdIntentDecorator.decorateWithUserProfileId @@ -24,7 +26,9 @@ class ProfileChooserActivityPresenter @Inject constructor( private val activity: AppCompatActivity, private val profileManagementController: ProfileManagementController, @EnableOnboardingFlowV2 - private val enableOnboardingFlowV2: PlatformParameterValue + private val enableOnboardingFlowV2: PlatformParameterValue, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { /** Adds [ProfileChooserFragment] to view. */ fun handleOnCreate(profileId: LegacyProfileId, parentScreen: ParentScreen) { @@ -40,6 +44,9 @@ class ProfileChooserActivityPresenter @Inject constructor( ) } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.profile_chooser_activity) if (getProfileChooserFragment() == null) { val profileChooserFragment = ProfileChooserFragment() diff --git a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenter.kt index e99c5330aaf..8a0e8ea7413 100644 --- a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenter.kt @@ -7,6 +7,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity +import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat import androidx.core.view.ViewCompat import androidx.fragment.app.Fragment @@ -29,11 +30,13 @@ import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.oppialogger.analytics.AnalyticsController import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.platformparameter.EnableEdgeToEdge import org.oppia.android.util.platformparameter.EnableMultipleClassrooms import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.toProfileIdPreservingZero @@ -79,7 +82,8 @@ class ProfileChooserFragmentPresenter @Inject constructor( private val analyticsController: AnalyticsController, private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory, private val resourceHandler: AppLanguageResourceHandler, - @EnableMultipleClassrooms private val enableMultipleClassrooms: PlatformParameterValue + @EnableMultipleClassrooms private val enableMultipleClassrooms: PlatformParameterValue, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var binding: ProfileSelectionFragmentBinding @@ -94,9 +98,11 @@ class ProfileChooserFragmentPresenter @Inject constructor( adminProfileId: LegacyProfileId, parentScreen: ParentScreen ): View? { - StatusBarColor.statusBarColorUpdate( - R.color.component_color_shared_profile_status_bar_color, activity, false - ) + if (!enableEdgeToEdge.value) { + StatusBarColor.statusBarColorUpdate( + R.color.component_color_shared_profile_status_bar_color, activity, false + ) + } if (parentScreen == ParentScreen.ADMIN_INTRO_SCREEN) { // The admin onboarding ends here in order to prevent the admin from seeing the onboarding @@ -125,6 +131,13 @@ class ProfileChooserFragmentPresenter @Inject constructor( binding.addProfileButton.setOnClickListener { addProfileButtonClickListener() } binding.addProfilePrompt.setOnClickListener { addProfileButtonClickListener() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToRootConstraintLayout( + activity, + binding.root as ConstraintLayout, + R.color.component_color_shared_profile_status_bar_color + ) + } return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenterV1.kt b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenterV1.kt index 615a9d4e476..3c70135464d 100644 --- a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenterV1.kt +++ b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenterV1.kt @@ -5,6 +5,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity +import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat import androidx.databinding.ObservableField import androidx.fragment.app.Fragment @@ -23,11 +24,13 @@ import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileChooserUiModel import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.oppialogger.analytics.AnalyticsController import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.platformparameter.EnableEdgeToEdge import org.oppia.android.util.platformparameter.EnableMultipleClassrooms import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.toProfileIdPreservingZero @@ -72,16 +75,19 @@ class ProfileChooserFragmentPresenterV1 @Inject constructor( private val oppiaLogger: OppiaLogger, private val analyticsController: AnalyticsController, private val multiTypeBuilderFactory: BindableAdapter.MultiTypeBuilder.Factory, - @EnableMultipleClassrooms private val enableMultipleClassrooms: PlatformParameterValue + @EnableMultipleClassrooms private val enableMultipleClassrooms: PlatformParameterValue, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var binding: ProfileChooserFragmentBinding val hasProfileEverBeenAddedValue = ObservableField(true) /** Binds ViewModel and sets up RecyclerView Adapter. */ fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? { - StatusBarColor.statusBarColorUpdate( - R.color.component_color_shared_profile_status_bar_color, activity, false - ) + if (!enableEdgeToEdge.value) { + StatusBarColor.statusBarColorUpdate( + R.color.component_color_shared_profile_status_bar_color, activity, false + ) + } binding = ProfileChooserFragmentBinding.inflate( inflater, container, @@ -98,6 +104,13 @@ class ProfileChooserFragmentPresenterV1 @Inject constructor( binding.profileRecyclerView.apply { adapter = createRecyclerViewAdapter() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToRootConstraintLayout( + activity, + binding.root as ConstraintLayout, + R.color.component_color_shared_profile_status_bar_color + ) + } return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/profileprogress/ProfilePictureActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/profileprogress/ProfilePictureActivityPresenter.kt index 47673489091..47f510abc0d 100644 --- a/app/src/main/java/org/oppia/android/app/profileprogress/ProfilePictureActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/profileprogress/ProfilePictureActivityPresenter.kt @@ -13,10 +13,13 @@ import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileAvatar import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.toProfileIdPreservingZero import org.oppia.android.util.statusbar.StatusBarColor import javax.inject.Inject @@ -26,15 +29,24 @@ import javax.inject.Inject class ProfilePictureActivityPresenter @Inject constructor( private val activity: AppCompatActivity, private val profileManagementController: ProfileManagementController, - private val oppiaLogger: OppiaLogger + private val oppiaLogger: OppiaLogger, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var profilePictureActivityViewModel: ProfilePictureActivityViewModel private lateinit var profileId: LegacyProfileId fun handleOnCreate(internalProfileId: Int) { - StatusBarColor.statusBarColorUpdate( - R.color.component_color_shared_profile_status_bar_color, activity, false - ) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } else { + StatusBarColor.statusBarColorUpdate( + R.color + .component_color_shared_profile_status_bar_color, + activity, + false + ) + } val binding = DataBindingUtil .setContentView( activity, @@ -49,10 +61,17 @@ class ProfilePictureActivityPresenter @Inject constructor( profileId = LegacyProfileId.newBuilder().setInternalId(internalProfileId).build() subscribeToProfileLiveData() - setUpToolbar() + val toolbar = setUpToolbar() + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + toolbar, + R.color.component_color_shared_profile_status_bar_color + ) + } } - private fun setUpToolbar() { + private fun setUpToolbar(): Toolbar { val toolbar = activity.findViewById( R.id.profile_picture_activity_toolbar ) as Toolbar @@ -60,6 +79,7 @@ class ProfilePictureActivityPresenter @Inject constructor( toolbar.setNavigationOnClickListener { activity.finish() } + return toolbar } private val profileLiveData: LiveData by lazy { diff --git a/app/src/main/java/org/oppia/android/app/profileprogress/ProfileProgressActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/profileprogress/ProfileProgressActivityPresenter.kt index d7d1e5517a1..565b1b40c78 100644 --- a/app/src/main/java/org/oppia/android/app/profileprogress/ProfileProgressActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/profileprogress/ProfileProgressActivityPresenter.kt @@ -7,7 +7,10 @@ import androidx.appcompat.widget.Toolbar import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.profile.ProfileManagementController +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.toProfileIdPreservingZero import javax.inject.Inject @@ -15,12 +18,16 @@ import javax.inject.Inject @ActivityScope class ProfileProgressActivityPresenter @Inject constructor( private val activity: AppCompatActivity, - private val profileManagementController: ProfileManagementController + private val profileManagementController: ProfileManagementController, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var profileId: LegacyProfileId fun handleOnCreate(internalProfileId: Int) { profileId = LegacyProfileId.newBuilder().setInternalId(internalProfileId).build() + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.profile_progress_activity) if (getProfileProgressFragment() == null) { activity.supportFragmentManager.beginTransaction().add( @@ -42,6 +49,13 @@ class ProfileProgressActivityPresenter @Inject constructor( toolbar.setNavigationOnClickListener { activity.finish() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToToolbarContainer( + activity, + toolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } } private fun getProfileProgressFragment(): ProfileProgressFragment? { diff --git a/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonActivityPresenter.kt index b65c7f59eea..2cdae466dbf 100644 --- a/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/resumelesson/ResumeLessonActivityPresenter.kt @@ -14,10 +14,13 @@ import org.oppia.android.app.model.ReadingTextSize import org.oppia.android.app.player.exploration.DefaultFontSizeStateListener import org.oppia.android.app.ui.R import org.oppia.android.app.utility.FontScaleConfigurationUtil +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.toProfileIdPreservingZero import javax.inject.Inject @@ -28,7 +31,9 @@ class ResumeLessonActivityPresenter @Inject constructor( private val activity: AppCompatActivity, private val profileManagementController: ProfileManagementController, private val fontScaleConfigurationUtil: FontScaleConfigurationUtil, - private val oppiaLogger: OppiaLogger + private val oppiaLogger: OppiaLogger, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var profileId: LegacyProfileId private lateinit var classroomId: String @@ -48,6 +53,9 @@ class ResumeLessonActivityPresenter @Inject constructor( parentScreen: ExplorationActivityParams.ParentScreen, explorationCheckpoint: ExplorationCheckpoint ) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding = DataBindingUtil.setContentView( activity, R.layout.resume_lesson_activity @@ -61,6 +69,13 @@ class ResumeLessonActivityPresenter @Inject constructor( this.parentScreen = parentScreen val resumeLessonToolbar = binding.resumeLessonActivityToolbar activity.setSupportActionBar(resumeLessonToolbar) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + resumeLessonToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } retrieveReadingTextSize().observe( activity as ResumeLessonActivity, diff --git a/app/src/main/java/org/oppia/android/app/settings/profile/ProfileEditActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/settings/profile/ProfileEditActivityPresenter.kt index ae929bfacfd..ee14fc30254 100644 --- a/app/src/main/java/org/oppia/android/app/settings/profile/ProfileEditActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/settings/profile/ProfileEditActivityPresenter.kt @@ -7,19 +7,26 @@ import androidx.appcompat.widget.Toolbar import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.model.ProfileEditActivityParams import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.util.extensions.getProtoExtra +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [ProfileEditActivity]. */ @ActivityScope class ProfileEditActivityPresenter @Inject constructor( - private val activity: AppCompatActivity + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var toolbar: Toolbar /** Handles onCreate function of [ProfileEditActivity]. */ fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.profile_edit_activity) setUpToolbar() val args = activity.intent.getProtoExtra( @@ -50,6 +57,13 @@ class ProfileEditActivityPresenter @Inject constructor( private fun setUpToolbar() { toolbar = activity.findViewById(R.id.profile_edit_toolbar) as Toolbar activity.setSupportActionBar(toolbar) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + toolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } } private fun getProfileEditFragment(): ProfileEditFragment? { diff --git a/app/src/main/java/org/oppia/android/app/settings/profile/ProfileListActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/settings/profile/ProfileListActivityPresenter.kt index 3137c068ecb..2a023cedc0a 100644 --- a/app/src/main/java/org/oppia/android/app/settings/profile/ProfileListActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/settings/profile/ProfileListActivityPresenter.kt @@ -4,17 +4,24 @@ import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [ProfileListActivity]. */ @ActivityScope class ProfileListActivityPresenter @Inject constructor( private val activity: AppCompatActivity, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { /** Handles onCreate method of [ProfileListActivity]. */ fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.title = resourceHandler.getStringInLocale(R.string.profile_list_activity_title) activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp) diff --git a/app/src/main/java/org/oppia/android/app/settings/profile/ProfileListFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/settings/profile/ProfileListFragmentPresenter.kt index 9119d4b37ca..5b73ebee72b 100644 --- a/app/src/main/java/org/oppia/android/app/settings/profile/ProfileListFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/settings/profile/ProfileListFragmentPresenter.kt @@ -11,6 +11,10 @@ import org.oppia.android.app.databinding.databinding.ProfileListProfileViewBindi import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.model.Profile import org.oppia.android.app.recyclerview.BindableAdapter +import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [ProfileListFragment]. */ @@ -19,7 +23,8 @@ class ProfileListFragmentPresenter @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, private val profileListViewModel: ProfileListViewModel, - private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory + private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private var isMultipane = false @@ -48,6 +53,16 @@ class ProfileListFragmentPresenter @Inject constructor( binding.profileListRecyclerView.apply { adapter = createRecyclerViewAdapter() } + + if (enableEdgeToEdge.value) { + binding.profileListToolbar?.let { toolbar -> + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + toolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + } return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/settings/profile/ProfileRenameActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/settings/profile/ProfileRenameActivityPresenter.kt index bfa944b5463..17a0c30bf46 100644 --- a/app/src/main/java/org/oppia/android/app/settings/profile/ProfileRenameActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/settings/profile/ProfileRenameActivityPresenter.kt @@ -5,14 +5,24 @@ import androidx.databinding.DataBindingUtil import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.databinding.databinding.ProfileRenameActivityBinding import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [ProfileRenameActivity]. */ @ActivityScope -class ProfileRenameActivityPresenter @Inject constructor(private val activity: AppCompatActivity) { +class ProfileRenameActivityPresenter @Inject constructor( + private val activity: AppCompatActivity, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue +) { /** Handles onCreate() of [ProfileRenameActivity]. */ fun handleOnCreate(profileId: Int) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp) @@ -29,6 +39,15 @@ class ProfileRenameActivityPresenter @Inject constructor(private val activity: A binding.profileRenameToolbar.setNavigationOnClickListener { (activity as ProfileRenameActivity).finish() } + + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.profileRenameToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + if (getProfileRenameFragment() == null) { val profileRenameFragment = ProfileRenameFragment.newInstance(profileId) activity.supportFragmentManager.beginTransaction() diff --git a/app/src/main/java/org/oppia/android/app/settings/profile/ProfileResetPinActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/settings/profile/ProfileResetPinActivityPresenter.kt index b69fbcbb278..7f2f9978c09 100644 --- a/app/src/main/java/org/oppia/android/app/settings/profile/ProfileResetPinActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/settings/profile/ProfileResetPinActivityPresenter.kt @@ -7,8 +7,11 @@ import org.oppia.android.app.databinding.databinding.ProfileResetPinActivityBind import org.oppia.android.app.model.ProfileResetPinActivityParams import org.oppia.android.app.settings.profile.ProfileResetPinActivity.Companion.PROFILE_RESET_PIN_ACTIVITY_PARAMS_KEY import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.util.extensions.getProtoExtra +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [ProfileResetPinActivity]. */ @@ -16,10 +19,15 @@ import javax.inject.Inject class ProfileResetPinActivityPresenter @Inject constructor( private val activity: AppCompatActivity, private val profileManagementController: ProfileManagementController, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { /** Handles onCreate() method of the [ProfileResetPinActivity]. */ fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp) @@ -41,6 +49,14 @@ class ProfileResetPinActivityPresenter @Inject constructor( (activity as ProfileResetPinActivity).finish() } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.profileResetPinToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + binding.apply { lifecycleOwner = activity } diff --git a/app/src/main/java/org/oppia/android/app/splash/SplashActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/splash/SplashActivityPresenter.kt index 534b4afc147..07080e9467a 100644 --- a/app/src/main/java/org/oppia/android/app/splash/SplashActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/splash/SplashActivityPresenter.kt @@ -37,6 +37,7 @@ import org.oppia.android.app.onboarding.PROFILE_CHOOSER_PARAMS_KEY import org.oppia.android.app.profile.ProfileChooserActivity import org.oppia.android.app.translation.AppLanguageLocaleHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.app.utility.lifecycle.LifecycleSafeTimerFactory import org.oppia.android.domain.locale.LocaleController import org.oppia.android.domain.onboarding.AppStartupStateController @@ -52,6 +53,7 @@ import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.extensions.putProtoExtra import org.oppia.android.util.locale.OppiaLocale import org.oppia.android.util.platformparameter.EnableAppAndOsDeprecation +import org.oppia.android.util.platformparameter.EnableEdgeToEdge import org.oppia.android.util.platformparameter.EnableMultipleClassrooms import org.oppia.android.util.platformparameter.EnableOnboardingFlowV2 import org.oppia.android.util.platformparameter.PlatformParameterValue @@ -160,7 +162,9 @@ class SplashActivityPresenter @Inject constructor( @EnableOnboardingFlowV2 private val enableOnboardingFlowV2Provider: PlatformParameterValue, @EnableMultipleClassrooms - private val enableMultipleClassroomsProvider: PlatformParameterValue + private val enableMultipleClassroomsProvider: PlatformParameterValue, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var startupMode: StartupMode @@ -244,6 +248,13 @@ class SplashActivityPresenter @Inject constructor( } fun subscribeToOnboardingFlow() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + EdgeToEdgeHelper.applyToRootConstraintLayout( + activity, + R.color.component_color_shared_activity_status_bar_color + ) + } val liveData = computeInitStateDataProvider().toLiveData() liveData.observe( activity, diff --git a/app/src/main/java/org/oppia/android/app/story/StoryActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/story/StoryActivityPresenter.kt index d40f887c5ef..5c984926cca 100644 --- a/app/src/main/java/org/oppia/android/app/story/StoryActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/story/StoryActivityPresenter.kt @@ -3,17 +3,26 @@ package org.oppia.android.app.story import androidx.appcompat.app.AppCompatActivity import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [StoryActivity]. */ @ActivityScope -class StoryActivityPresenter @Inject constructor(private val activity: AppCompatActivity) { +class StoryActivityPresenter @Inject constructor( + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue +) { fun handleOnCreate( internalProfileId: Int, classroomId: String, topicId: String, storyId: String ) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.story_activity) if (getStoryFragment() == null) { activity.supportFragmentManager.beginTransaction().add( diff --git a/app/src/main/java/org/oppia/android/app/story/StoryFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/story/StoryFragmentPresenter.kt index 6e37c11cd27..fb64387c5d8 100644 --- a/app/src/main/java/org/oppia/android/app/story/StoryFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/story/StoryFragmentPresenter.kt @@ -32,6 +32,7 @@ import org.oppia.android.app.story.storyitemviewmodel.StoryItemViewModel import org.oppia.android.app.topic.RouteToResumeLessonListener import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.exploration.ExplorationDataController import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.oppialogger.analytics.AnalyticsController @@ -41,6 +42,8 @@ import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.gcsresource.DefaultResourceBucketName import org.oppia.android.util.parser.html.HtmlParser import org.oppia.android.util.parser.html.TopicHtmlParserEntityType +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [StoryFragment]. */ @@ -54,7 +57,8 @@ class StoryFragmentPresenter @Inject constructor( @DefaultResourceBucketName private val resourceBucketName: String, @TopicHtmlParserEntityType private val entityType: String, private val resourceHandler: AppLanguageResourceHandler, - private val multiTypeBuilderFactory: BindableAdapter.MultiTypeBuilder.Factory + private val multiTypeBuilderFactory: BindableAdapter.MultiTypeBuilder.Factory, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private val routeToExplorationListener = activity as RouteToExplorationListener private val routeToResumeLessonListener = activity as RouteToResumeLessonListener @@ -109,6 +113,14 @@ class StoryFragmentPresenter @Inject constructor( it.lifecycleOwner = fragment it.viewModel = storyViewModel } + + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.storyToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/survey/SurveyActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/survey/SurveyActivityPresenter.kt index 6f1e50d2c1d..c1739c1521f 100644 --- a/app/src/main/java/org/oppia/android/app/survey/SurveyActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/survey/SurveyActivityPresenter.kt @@ -9,7 +9,10 @@ import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.model.SurveyFragmentArguments import org.oppia.android.app.survey.SurveyFragment.Companion.SURVEY_FRAGMENT_ARGUMENTS_KEY import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.util.extensions.putProto +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.CurrentUserProfileIdIntentDecorator.decorateWithUserProfileId import javax.inject.Inject @@ -17,7 +20,10 @@ private const val TAG_SURVEY_FRAGMENT = "TAG_SURVEY_FRAGMENT" /** The Presenter for [SurveyActivity]. */ @ActivityScope -class SurveyActivityPresenter @Inject constructor(private val activity: AppCompatActivity) { +class SurveyActivityPresenter @Inject constructor( + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue +) { private lateinit var binding: SurveyActivityBinding fun handleOnCreate( @@ -25,6 +31,9 @@ class SurveyActivityPresenter @Inject constructor(private val activity: AppCompa topicId: String, explorationId: String ) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } binding = DataBindingUtil.setContentView(activity, R.layout.survey_activity) binding.apply { lifecycleOwner = activity diff --git a/app/src/main/java/org/oppia/android/app/survey/SurveyFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/survey/SurveyFragmentPresenter.kt index bd3844c21bf..c8736c0b22a 100644 --- a/app/src/main/java/org/oppia/android/app/survey/SurveyFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/survey/SurveyFragmentPresenter.kt @@ -28,11 +28,15 @@ import org.oppia.android.app.survey.surveyitemviewmodel.NpsItemsViewModel import org.oppia.android.app.survey.surveyitemviewmodel.SurveyAnswerItemViewModel import org.oppia.android.app.survey.surveyitemviewmodel.UserTypeItemsViewModel import org.oppia.android.app.translation.AppLanguageResourceHandler +import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.oppialogger.analytics.AnalyticsController import org.oppia.android.domain.survey.SurveyProgressController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The presenter for [SurveyFragment]. */ @@ -44,7 +48,8 @@ class SurveyFragmentPresenter @Inject constructor( private val surveyViewModel: SurveyViewModel, private val multiTypeBuilderFactory: BindableAdapter.MultiTypeBuilder.Factory, private val resourceHandler: AppLanguageResourceHandler, - private val analyticsController: AnalyticsController + private val analyticsController: AnalyticsController, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { private val ephemeralQuestionLiveData: LiveData> by lazy { surveyProgressController.getCurrentQuestion().toLiveData() @@ -87,6 +92,13 @@ class SurveyFragmentPresenter @Inject constructor( val dialogFragment = ExitSurveyConfirmationDialogFragment.newInstance(profileId) dialogFragment.showNow(fragment.childFragmentManager, TAG_EXIT_SURVEY_CONFIRMATION_DIALOG) } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + surveyToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } binding.surveyAnswersRecyclerView.apply { adapter = createRecyclerViewAdapter() diff --git a/app/src/main/java/org/oppia/android/app/topic/TopicActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/topic/TopicActivityPresenter.kt index 18b52063bfa..58123b10db7 100755 --- a/app/src/main/java/org/oppia/android/app/topic/TopicActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/topic/TopicActivityPresenter.kt @@ -8,7 +8,10 @@ import org.oppia.android.app.model.TopicFragmentArguments import org.oppia.android.app.spotlight.SpotlightFragment import org.oppia.android.app.spotlight.SpotlightManager import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.util.extensions.putProto +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.CurrentUserProfileIdIntentDecorator.decorateWithUserProfileId import javax.inject.Inject @@ -17,7 +20,10 @@ const val TOPIC_FRAGMENT_ARGUMENTS_KEY = "TopicFragment.arguments" /** The presenter for [TopicActivity]. */ @ActivityScope -class TopicActivityPresenter @Inject constructor(private val activity: AppCompatActivity) { +class TopicActivityPresenter @Inject constructor( + private val activity: AppCompatActivity, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue +) { private lateinit var classroomId: String private lateinit var topicId: String @@ -29,6 +35,9 @@ class TopicActivityPresenter @Inject constructor(private val activity: AppCompat ) { this.topicId = topicId this.classroomId = classroomId + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.topic_activity) if (getTopicFragment() == null) { diff --git a/app/src/main/java/org/oppia/android/app/topic/TopicFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/topic/TopicFragmentPresenter.kt index 7d27b7eeef4..7369dfcd311 100644 --- a/app/src/main/java/org/oppia/android/app/topic/TopicFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/topic/TopicFragmentPresenter.kt @@ -18,9 +18,11 @@ import org.oppia.android.app.spotlight.SpotlightShape import org.oppia.android.app.spotlight.SpotlightTarget import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.oppialogger.analytics.AnalyticsController import org.oppia.android.util.accessibility.AccessibilityService +import org.oppia.android.util.platformparameter.EnableEdgeToEdge import org.oppia.android.util.platformparameter.EnableTopicInfoTab import org.oppia.android.util.platformparameter.EnableTopicPracticeTab import org.oppia.android.util.platformparameter.PlatformParameterValue @@ -36,7 +38,8 @@ class TopicFragmentPresenter @Inject constructor( private val analyticsController: AnalyticsController, @EnableTopicInfoTab private val enableTopicInfoTabFlag: PlatformParameterValue, @EnableTopicPracticeTab private val enableTopicPracticeTabFlag: PlatformParameterValue, - private val resourceHandler: AppLanguageResourceHandler + private val resourceHandler: AppLanguageResourceHandler, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) { @Inject lateinit var accessibilityService: AccessibilityService @@ -95,6 +98,14 @@ class TopicFragmentPresenter @Inject constructor( ) } + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.topicToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } + return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivityPresenter.kt index 46d7e39b549..fc76d424c45 100644 --- a/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/topic/questionplayer/QuestionPlayerActivityPresenter.kt @@ -21,12 +21,15 @@ import org.oppia.android.app.player.exploration.TAG_HINTS_AND_SOLUTION_DIALOG import org.oppia.android.app.topic.questionplayer.QuestionPlayerActivity.Companion.QUESTION_PLAYER_ACTIVITY_PARAMS_KEY import org.oppia.android.app.ui.R import org.oppia.android.app.utility.FontScaleConfigurationUtil +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.domain.question.QuestionTrainingController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.extensions.getProtoExtra +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.toProfileIdPreservingZero import javax.inject.Inject @@ -40,7 +43,9 @@ class QuestionPlayerActivityPresenter @Inject constructor( private val questionTrainingController: QuestionTrainingController, private val oppiaLogger: OppiaLogger, private val profileManagementController: ProfileManagementController, - private val fontScaleConfigurationUtil: FontScaleConfigurationUtil + private val fontScaleConfigurationUtil: FontScaleConfigurationUtil, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { private lateinit var profileId: LegacyProfileId private lateinit var state: State @@ -50,6 +55,9 @@ class QuestionPlayerActivityPresenter @Inject constructor( fun handleOnCreate(profileId: LegacyProfileId) { this.profileId = profileId + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding = DataBindingUtil.setContentView( activity, R.layout.question_player_activity @@ -60,6 +68,13 @@ class QuestionPlayerActivityPresenter @Inject constructor( } activity.setSupportActionBar(binding.questionPlayerToolbar) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + binding.questionPlayerToolbar, + R.color.component_color_shared_activity_status_bar_color + ) + } binding.questionPlayerToolbar.setNavigationOnClickListener { activity.onBackPressedDispatcher.onBackPressed() diff --git a/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivityPresenter.kt index 9bae3d51e64..b70a7158bd7 100644 --- a/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/topic/revisioncard/RevisionCardActivityPresenter.kt @@ -19,6 +19,7 @@ import org.oppia.android.app.player.exploration.BottomSheetOptionsMenu import org.oppia.android.app.player.exploration.DefaultFontSizeStateListener import org.oppia.android.app.ui.R import org.oppia.android.app.utility.FontScaleConfigurationUtil +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.oppialogger.analytics.AnalyticsController import org.oppia.android.domain.profile.ProfileManagementController @@ -27,6 +28,8 @@ import org.oppia.android.domain.translation.TranslationController import org.oppia.android.util.accessibility.AccessibilityService import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.toProfileIdPreservingZero import javax.inject.Inject @@ -40,6 +43,8 @@ class RevisionCardActivityPresenter @Inject constructor( private val translationController: TranslationController, private val profileManagementController: ProfileManagementController, private val fontScaleConfigurationUtil: FontScaleConfigurationUtil, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { @Inject lateinit var accessibilityService: AccessibilityService @@ -57,6 +62,9 @@ class RevisionCardActivityPresenter @Inject constructor( subtopicId: Int, subtopicListSize: Int ) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } val binding = DataBindingUtil.setContentView( activity, R.layout.revision_card_activity @@ -79,6 +87,13 @@ class RevisionCardActivityPresenter @Inject constructor( revisionCardToolbar = binding.revisionCardToolbar revisionCardToolbarTitle = binding.revisionCardToolbarTitle activity.setSupportActionBar(revisionCardToolbar) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + revisionCardToolbar, + R.color.component_color_revision_card_activity_status_bar_color + ) + } activity.supportActionBar?.setDisplayShowTitleEnabled(false) binding.revisionCardToolbar.setNavigationOnClickListener { diff --git a/app/src/main/java/org/oppia/android/app/topic/studyguide/StudyGuideActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/topic/studyguide/StudyGuideActivityPresenter.kt index 27e8c03b456..12ffb95a589 100644 --- a/app/src/main/java/org/oppia/android/app/topic/studyguide/StudyGuideActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/topic/studyguide/StudyGuideActivityPresenter.kt @@ -19,6 +19,7 @@ import org.oppia.android.app.player.exploration.DefaultFontSizeStateListener import org.oppia.android.app.topic.revisioncard.ReturnToTopicClickListener import org.oppia.android.app.ui.R import org.oppia.android.app.utility.FontScaleConfigurationUtil +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.oppialogger.analytics.AnalyticsController import org.oppia.android.domain.profile.ProfileManagementController @@ -27,6 +28,8 @@ import org.oppia.android.domain.translation.TranslationController import org.oppia.android.util.accessibility.AccessibilityService import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.profile.toProfileIdPreservingZero import javax.inject.Inject @@ -40,6 +43,8 @@ class StudyGuideActivityPresenter @Inject constructor( private val translationController: TranslationController, private val profileManagementController: ProfileManagementController, private val fontScaleConfigurationUtil: FontScaleConfigurationUtil, + @EnableEdgeToEdge + private val enableEdgeToEdge: PlatformParameterValue ) { @Inject lateinit var accessibilityService: AccessibilityService @@ -58,6 +63,9 @@ class StudyGuideActivityPresenter @Inject constructor( subtopicIndex: Int, subtopicListSize: Int ) { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } activity.setContentView(R.layout.study_guide_activity) this.profileId = profileId this.topicId = topicId @@ -73,6 +81,13 @@ class StudyGuideActivityPresenter @Inject constructor( studyGuideToolbar = activity.findViewById(R.id.study_guide_toolbar) studyGuideToolbarTitle = activity.findViewById(R.id.study_guide_toolbar_title) activity.setSupportActionBar(studyGuideToolbar) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToAppBarLayout( + activity, + studyGuideToolbar, + R.color.component_color_revision_card_activity_status_bar_color + ) + } activity.supportActionBar?.setDisplayShowTitleEnabled(false) studyGuideToolbar.setNavigationOnClickListener { diff --git a/app/src/main/java/org/oppia/android/app/utility/edgetoedge/BUILD.bazel b/app/src/main/java/org/oppia/android/app/utility/edgetoedge/BUILD.bazel new file mode 100644 index 00000000000..485a6ec8a03 --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/utility/edgetoedge/BUILD.bazel @@ -0,0 +1,17 @@ +""" +Edge-to-edge window inset handling shared by app UI flows. +""" + +load("@io_bazel_rules_kotlin//kotlin:android.bzl", "kt_android_library") + +kt_android_library( + name = "edge_to_edge_helper", + srcs = ["EdgeToEdgeHelper.kt"], + visibility = ["//app:app_visibility"], + deps = [ + "//third_party:androidx_annotation_annotation", + "//third_party:androidx_appcompat_appcompat", + "//third_party:androidx_constraintlayout_constraintlayout", + "//third_party:androidx_core_core-ktx", + ], +) diff --git a/app/src/main/java/org/oppia/android/app/utility/edgetoedge/EdgeToEdgeHelper.kt b/app/src/main/java/org/oppia/android/app/utility/edgetoedge/EdgeToEdgeHelper.kt new file mode 100644 index 00000000000..75f98f6130c --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/utility/edgetoedge/EdgeToEdgeHelper.kt @@ -0,0 +1,432 @@ +package org.oppia.android.app.utility.edgetoedge + +import android.os.Build +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.LinearLayout +import androidx.annotation.ColorRes +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.constraintlayout.widget.ConstraintSet +import androidx.core.content.ContextCompat +import androidx.core.graphics.Insets +import androidx.core.view.ViewCompat +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat +import java.util.WeakHashMap + +/** + * Utility that dispatches edge-to-edge window insets to activity toolbars, navigation drawers, + * and no-toolbar screens while the `EnableEdgeToEdge` platform parameter gates the Android 15 + * rollout. + */ +object EdgeToEdgeHelper { + private const val STATUS_BAR_SPACER_TAG = "oppia_edge_to_edge_status_bar_spacer" + + private val initialPaddings = WeakHashMap() + private val initialMargins = WeakHashMap() + + /** + * Enables manual edge-to-edge window dispatch for [activity]. Must be called before + * [AppCompatActivity.setContentView]. + */ + fun enableEdgeToEdgeDispatch(activity: AppCompatActivity) { + WindowCompat.setDecorFitsSystemWindows(activity.window, false) + } + + /** + * Applies edge-to-edge insets for activities whose root vertical `LinearLayout` directly + * contains the [toolbar] (e.g. Home, Options). Inserts a status-bar spacer colored with + * [statusBarColorRes] at the top of that `LinearLayout`. If the parent is not a `LinearLayout` + * (e.g. `ConstraintLayout` in AdminPin / sw600dp AdminControls), adds a separately colored + * status-bar spacer without changing the toolbar's background. + */ + fun applyToToolbarContainer( + activity: AppCompatActivity, + toolbar: Toolbar, + @ColorRes statusBarColorRes: Int + ) { + val parent = toolbar.parent + if (parent !is LinearLayout) { + applyAsTopBar(activity, toolbar, statusBarColorRes) + return + } + val contentLayout = parent + val spacer = getOrCreateLinearStatusBarSpacer( + activity, contentLayout, statusBarColorRes + ) + + ViewCompat.setOnApplyWindowInsetsListener(spacer) { view, insets -> + val bars = insets.systemBarsWithCutout() + view.layoutParams.height = bars.top + view.requestLayout() + insets + } + ViewCompat.setOnApplyWindowInsetsListener(contentLayout) { view, insets -> + val bars = insets.systemBarsWithCutout() + view.applyInsetPadding(bars, applyLeft = true, applyRight = true, applyBottom = true) + insets + } + + disableDecorAncestorFits(activity) + applyRootInsetsIfAvailable(contentLayout) { bars -> + spacer.layoutParams.height = bars.top + spacer.requestLayout() + contentLayout.applyInsetPadding( + bars, applyLeft = true, applyRight = true, applyBottom = true + ) + } + disableNavBarContrast(activity) + } + + /** + * Applies edge-to-edge insets for activities where the [toolbar] is wrapped in an app-bar + * `LinearLayout` or `AppBarLayout` (e.g. AppLanguage, FAQ). Paints the wrapper with + * [statusBarColorRes] and adds top padding equal to the status-bar inset; cutout-horizontal + * and navigation-bar-bottom padding is applied to `android.R.id.content`. Same fallback as + * [applyToToolbarContainer] when the parent is not a `LinearLayout`. + */ + fun applyToAppBarLayout( + activity: AppCompatActivity, + toolbar: Toolbar, + @ColorRes statusBarColorRes: Int + ) { + val parent = toolbar.parent + if (parent !is LinearLayout) { + applyAsTopBar(activity, toolbar, statusBarColorRes) + return + } + val appBarLayout: LinearLayout = parent + appBarLayout.setBackgroundColor(ContextCompat.getColor(activity, statusBarColorRes)) + val contentRoot = activity.findViewById(android.R.id.content) + + ViewCompat.setOnApplyWindowInsetsListener(appBarLayout) { view, insets -> + val bars = insets.systemBarsWithCutout() + view.applyInsetPadding(bars, applyTop = true) + insets + } + ViewCompat.setOnApplyWindowInsetsListener(contentRoot) { view, insets -> + val bars = insets.systemBarsWithCutout() + view.applyInsetPadding(bars, applyLeft = true, applyRight = true, applyBottom = true) + insets + } + + disableDecorAncestorFits(activity) + applyRootInsetsIfAvailable(appBarLayout) { bars -> + appBarLayout.applyInsetPadding(bars, applyTop = true) + contentRoot.applyInsetPadding( + bars, applyLeft = true, applyRight = true, applyBottom = true + ) + } + disableNavBarContrast(activity) + } + + /** + * Applies edge-to-edge insets for the side navigation drawer. Inserts a status-bar spacer + * colored with [statusBarColorRes] at the top of [drawerContentLayout], clears + * [navigationView]'s `fitsSystemWindows` and replaces its inset listener with a no-op so its + * default scrim does not paint over the drawer's system-bar area, and applies RTL-aware side + * and bottom padding to [drawerRoot]. + */ + fun applyToNavigationDrawer( + activity: AppCompatActivity, + drawerRoot: View, + drawerContentLayout: LinearLayout, + navigationView: View, + @ColorRes statusBarColorRes: Int + ) { + navigationView.fitsSystemWindows = false + + val spacer = getOrCreateLinearStatusBarSpacer( + activity, drawerContentLayout, statusBarColorRes + ) + ViewCompat.setOnApplyWindowInsetsListener(spacer) { view, insets -> + val bars = insets.systemBarsWithCutout() + view.layoutParams.height = bars.top + view.requestLayout() + insets + } + + ViewCompat.setOnApplyWindowInsetsListener(navigationView) { _, insets -> insets } + + ViewCompat.setOnApplyWindowInsetsListener(drawerRoot) { view, insets -> + val bars = insets.systemBarsWithCutout() + val isRtl = ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_RTL + view.applyInsetPadding( + bars, + applyLeft = !isRtl, + applyRight = isRtl, + applyBottom = true + ) + insets + } + } + + /** + * Applies edge-to-edge insets to a no-toolbar [ConstraintLayout]. Adds a status-bar spacer using + * [statusBarColorRes], and applies system-bar and display-cutout padding while preserving the + * layout's original padding. [statusBarLight] controls whether the status bar uses dark icons. + * + * Returns the spacer so callers such as onboarding can update its color with the current page. + */ + fun applyToRootConstraintLayout( + activity: AppCompatActivity, + rootLayout: ConstraintLayout, + @ColorRes statusBarColorRes: Int, + statusBarLight: Boolean = false + ): View { + val contentRoot = activity.findViewById(android.R.id.content) + val spacer = getOrCreateOverlayStatusBarSpacer(activity, contentRoot, statusBarColorRes) + + ViewCompat.setOnApplyWindowInsetsListener(spacer) { view, insets -> + val bars = insets.systemBarsWithCutout() + view.layoutParams.height = bars.top + view.requestLayout() + insets + } + ViewCompat.setOnApplyWindowInsetsListener(rootLayout) { view, insets -> + val bars = insets.systemBarsWithCutout() + view.applyInsetPadding( + bars, + applyLeft = true, + applyTop = true, + applyRight = true, + applyBottom = true + ) + insets + } + + disableDecorAncestorFits(activity) + applyRootInsetsIfAvailable(rootLayout) { bars -> + spacer.layoutParams.height = bars.top + spacer.requestLayout() + rootLayout.applyInsetPadding( + bars, + applyLeft = true, + applyTop = true, + applyRight = true, + applyBottom = true + ) + } + WindowCompat.getInsetsController(activity.window, rootLayout) + ?.isAppearanceLightStatusBars = statusBarLight + disableNavBarContrast(activity) + ViewCompat.requestApplyInsets(contentRoot) + + return spacer + } + + /** + * Applies no-toolbar insets when the binding root is unavailable, such as in the splash + * presenter's post-parameter-loading path. + */ + fun applyToRootConstraintLayout( + activity: AppCompatActivity, + @ColorRes statusBarColorRes: Int, + statusBarLight: Boolean = false + ): View { + val content = activity.findViewById(android.R.id.content) + val rootLayout = content.getChildAt(0) as ConstraintLayout + return applyToRootConstraintLayout( + activity, + rootLayout, + statusBarColorRes, + statusBarLight + ) + } + + // Used when the toolbar's parent is not a LinearLayout. A separate spacer preserves the + // toolbar's original color instead of turning the whole toolbar into the status-bar color. + private fun applyAsTopBar( + activity: AppCompatActivity, + topBar: View, + @ColorRes statusBarColorRes: Int + ) { + val contentRoot = activity.findViewById(android.R.id.content) + val topBarParent = topBar.parent + val spacer = if (topBarParent is ConstraintLayout && topBar.id != View.NO_ID) { + getOrCreateConstrainedStatusBarSpacer( + activity, topBarParent, topBar, statusBarColorRes + ) + } else { + getOrCreateOverlayStatusBarSpacer(activity, contentRoot, statusBarColorRes).also { + initialMargins.getOrPut(topBar) { topBar.captureMargins() } + } + } + + ViewCompat.setOnApplyWindowInsetsListener(spacer) { view, insets -> + val bars = insets.systemBarsWithCutout() + view.layoutParams.height = bars.top + view.requestLayout() + if (topBarParent !is ConstraintLayout) { + topBar.applyTopInsetMargin(bars.top) + } + insets + } + ViewCompat.setOnApplyWindowInsetsListener(contentRoot) { view, insets -> + val bars = insets.systemBarsWithCutout() + view.applyInsetPadding(bars, applyLeft = true, applyRight = true, applyBottom = true) + insets + } + + disableDecorAncestorFits(activity) + applyRootInsetsIfAvailable(spacer) { bars -> + spacer.layoutParams.height = bars.top + spacer.requestLayout() + if (topBarParent !is ConstraintLayout) { + topBar.applyTopInsetMargin(bars.top) + } + contentRoot.applyInsetPadding( + bars, applyLeft = true, applyRight = true, applyBottom = true + ) + } + disableNavBarContrast(activity) + } + + private fun getOrCreateLinearStatusBarSpacer( + activity: AppCompatActivity, + parent: LinearLayout, + @ColorRes statusBarColorRes: Int + ): View { + val spacer = parent.findDirectStatusBarSpacer() ?: View(activity).also { + it.tag = STATUS_BAR_SPACER_TAG + it.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0) + parent.addView(it, 0) + } + spacer.setBackgroundColor(ContextCompat.getColor(activity, statusBarColorRes)) + return spacer + } + + private fun getOrCreateConstrainedStatusBarSpacer( + activity: AppCompatActivity, + parent: ConstraintLayout, + topBar: View, + @ColorRes statusBarColorRes: Int + ): View { + val spacer = parent.findDirectStatusBarSpacer() ?: View(activity).also { + it.id = View.generateViewId() + it.tag = STATUS_BAR_SPACER_TAG + it.layoutParams = ConstraintLayout.LayoutParams(0, 0) + parent.addView(it) + } + spacer.setBackgroundColor(ContextCompat.getColor(activity, statusBarColorRes)) + + val originalMargins = initialMargins.getOrPut(topBar) { topBar.captureMargins() } + ConstraintSet().apply { + clone(parent) + connect(spacer.id, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP) + connect(spacer.id, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START) + connect(spacer.id, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END) + clear(topBar.id, ConstraintSet.TOP) + connect( + topBar.id, + ConstraintSet.TOP, + spacer.id, + ConstraintSet.BOTTOM, + originalMargins.top + ) + applyTo(parent) + } + return spacer + } + + private fun getOrCreateOverlayStatusBarSpacer( + activity: AppCompatActivity, + contentRoot: View, + @ColorRes statusBarColorRes: Int + ): View { + val root = contentRoot as ViewGroup + val spacer = root.findDirectStatusBarSpacer() ?: View(activity).also { + it.tag = STATUS_BAR_SPACER_TAG + it.layoutParams = FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + 0, + Gravity.TOP + ) + root.addView(it) + } + spacer.setBackgroundColor(ContextCompat.getColor(activity, statusBarColorRes)) + return spacer + } + + private fun ViewGroup.findDirectStatusBarSpacer(): View? = + (0 until childCount) + .map(::getChildAt) + .firstOrNull { it.tag == STATUS_BAR_SPACER_TAG } + + private fun WindowInsetsCompat.systemBarsWithCutout(): Insets = getInsets( + WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() + ) + + // AppCompat Bridge themes re-apply status-bar top padding via legacy fitsSystemWindows + // dispatch on ancestors like FitWindowsLinearLayout; clearing those flags avoids double-counting + // the top inset. + private fun disableDecorAncestorFits(activity: AppCompatActivity) { + val contentRoot = activity.findViewById(android.R.id.content) + var ancestor: View? = contentRoot.parent as? View + while (ancestor != null) { + if (ancestor.fitsSystemWindows) { + ancestor.fitsSystemWindows = false + ancestor.setPadding(0, 0, 0, 0) + } + ancestor = ancestor.parent as? View + } + } + + // On activity-recreate the dispatch listener may not fire on the first frame; seed the spacer + // and padding synchronously from getRootWindowInsets to avoid a momentary full-screen flash. + private fun applyRootInsetsIfAvailable(view: View, apply: (Insets) -> Unit) { + val rootInsets = ViewCompat.getRootWindowInsets(view) ?: return + apply(rootInsets.systemBarsWithCutout()) + } + + private fun disableNavBarContrast(activity: AppCompatActivity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + activity.window.isNavigationBarContrastEnforced = false + } + } + + private fun View.applyInsetPadding( + insets: Insets, + applyLeft: Boolean = false, + applyTop: Boolean = false, + applyRight: Boolean = false, + applyBottom: Boolean = false + ) { + val initial = initialPaddings.getOrPut(this) { capturePadding() } + setPadding( + initial.left + if (applyLeft) insets.left else 0, + initial.top + if (applyTop) insets.top else 0, + initial.right + if (applyRight) insets.right else 0, + initial.bottom + if (applyBottom) insets.bottom else 0 + ) + } + + private fun View.applyTopInsetMargin(topInset: Int) { + val marginParams = layoutParams as? ViewGroup.MarginLayoutParams ?: return + val initial = initialMargins.getOrPut(this) { captureMargins() } + if (marginParams.topMargin != initial.top + topInset) { + marginParams.topMargin = initial.top + topInset + layoutParams = marginParams + } + } + + private fun View.capturePadding() = Padding(paddingLeft, paddingTop, paddingRight, paddingBottom) + + private fun View.captureMargins(): Margins { + val marginParams = layoutParams as? ViewGroup.MarginLayoutParams + return Margins( + marginParams?.leftMargin ?: 0, + marginParams?.topMargin ?: 0, + marginParams?.rightMargin ?: 0, + marginParams?.bottomMargin ?: 0 + ) + } + + private data class Padding(val left: Int, val top: Int, val right: Int, val bottom: Int) + + private data class Margins(val left: Int, val top: Int, val right: Int, val bottom: Int) +} diff --git a/app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivityPresenter.kt index 6108bb518c5..fbee28395cd 100644 --- a/app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivityPresenter.kt @@ -1,13 +1,17 @@ package org.oppia.android.app.walkthrough import androidx.appcompat.app.AppCompatActivity +import androidx.constraintlayout.widget.ConstraintLayout import androidx.databinding.DataBindingUtil import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.databinding.databinding.WalkthroughActivityBinding import org.oppia.android.app.ui.R +import org.oppia.android.app.utility.edgetoedge.EdgeToEdgeHelper import org.oppia.android.app.walkthrough.end.WalkthroughFinalFragment import org.oppia.android.app.walkthrough.topiclist.WalkthroughTopicListFragment import org.oppia.android.app.walkthrough.welcome.WalkthroughWelcomeFragment +import org.oppia.android.util.platformparameter.EnableEdgeToEdge +import org.oppia.android.util.platformparameter.PlatformParameterValue import org.oppia.android.util.statusbar.StatusBarColor import javax.inject.Inject @@ -15,12 +19,16 @@ import javax.inject.Inject @ActivityScope class WalkthroughActivityPresenter @Inject constructor( private val activity: AppCompatActivity, - private val walkthroughViewModel: WalkthroughViewModel + private val walkthroughViewModel: WalkthroughViewModel, + @EnableEdgeToEdge private val enableEdgeToEdge: PlatformParameterValue ) : WalkthroughActivityListener { private lateinit var topicId: String private lateinit var binding: WalkthroughActivityBinding fun handleOnCreate() { + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.enableEdgeToEdgeDispatch(activity) + } binding = DataBindingUtil.setContentView(activity, R.layout.walkthrough_activity) binding.apply { @@ -28,11 +36,20 @@ class WalkthroughActivityPresenter @Inject constructor( presenter = this@WalkthroughActivityPresenter lifecycleOwner = activity } - StatusBarColor.statusBarColorUpdate( - R.color.component_color_walkthrough_activity_status_bar_color, - activity, - true - ) + if (enableEdgeToEdge.value) { + EdgeToEdgeHelper.applyToRootConstraintLayout( + activity, + binding.root as ConstraintLayout, + R.color.component_color_walkthrough_activity_status_bar_color, + statusBarLight = true + ) + } else { + StatusBarColor.statusBarColorUpdate( + R.color.component_color_walkthrough_activity_status_bar_color, + activity, + true + ) + } val currentFragmentIndex = walkthroughViewModel.currentProgress.get()?.minus(1) if (currentFragmentIndex == -1 && getWalkthroughWelcomeFragment() == null) { diff --git a/app/src/test/java/org/oppia/android/app/utility/edgetoedge/EdgeToEdgeHelperTest.kt b/app/src/test/java/org/oppia/android/app/utility/edgetoedge/EdgeToEdgeHelperTest.kt new file mode 100644 index 00000000000..0fbf6e6c61b --- /dev/null +++ b/app/src/test/java/org/oppia/android/app/utility/edgetoedge/EdgeToEdgeHelperTest.kt @@ -0,0 +1,298 @@ +package org.oppia.android.app.utility.edgetoedge + +import android.app.Application +import android.content.Context +import android.content.pm.ActivityInfo +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.LinearLayout +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.constraintlayout.widget.ConstraintSet +import androidx.core.content.ContextCompat +import androidx.core.graphics.Insets +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.test.core.app.ActivityScenario +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.oppia.android.app.test.R +import org.oppia.android.app.testing.activity.TestActivity +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode + +/** Tests for [EdgeToEdgeHelper]'s window-inset behavior. */ +// FunctionName: test names are conventionally named with underscores. +@Suppress("FunctionName") +@RunWith(AndroidJUnit4::class) +@Config(application = Application::class) +@LooperMode(LooperMode.Mode.PAUSED) +class EdgeToEdgeHelperTest { + private lateinit var context: Context + + @Before + fun setUp() { + context = ApplicationProvider.getApplicationContext() + TestActivity.registerActivityInfo( + context, + ActivityInfo().apply { + name = AppCompatActivity::class.java.name + packageName = context.packageName + theme = R.style.OppiaThemeWithoutActionBar + } + ) + } + + @Test + fun testApplyToToolbarContainer_twice_createsOneSpacerAndPreservesPadding() { + launchTestActivity { activity -> + val contentLayout = LinearLayout(activity).apply { + orientation = LinearLayout.VERTICAL + setPadding(1, 2, 3, 4) + } + val toolbar = Toolbar(activity).apply { setBackgroundColor(Color.RED) } + contentLayout.addView(toolbar) + activity.setContentView(contentLayout) + + EdgeToEdgeHelper.applyToToolbarContainer(activity, toolbar, STATUS_BAR_COLOR) + EdgeToEdgeHelper.applyToToolbarContainer(activity, toolbar, STATUS_BAR_COLOR) + dispatchInsets(contentLayout) + + assertThat(contentLayout.childCount).isEqualTo(2) + assertThat(contentLayout.getChildAt(1)).isSameInstanceAs(toolbar) + assertThat(contentLayout.paddingLeft).isEqualTo(16) + assertThat(contentLayout.paddingTop).isEqualTo(2) + assertThat(contentLayout.paddingRight).isEqualTo(38) + assertThat(contentLayout.paddingBottom).isEqualTo(44) + assertThat(contentLayout.getChildAt(0).layoutParams.height).isEqualTo(25) + assertThat(toolbar.backgroundColor).isEqualTo(Color.RED) + + dispatchInsets(contentLayout) + + assertThat(contentLayout.paddingLeft).isEqualTo(16) + assertThat(contentLayout.paddingRight).isEqualTo(38) + assertThat(contentLayout.paddingBottom).isEqualTo(44) + } + } + + @Test + fun testApplyToAppBarLayout_insetsPreserveExistingPaddingAndUseStatusBarColor() { + launchTestActivity { activity -> + val root = LinearLayout(activity).apply { orientation = LinearLayout.VERTICAL } + val appBarLayout = LinearLayout(activity).apply { + orientation = LinearLayout.VERTICAL + setPadding(1, 2, 3, 4) + } + val toolbar = Toolbar(activity).apply { setBackgroundColor(Color.RED) } + appBarLayout.addView(toolbar) + root.addView(appBarLayout) + activity.setContentView(root) + val contentRoot = activity.findViewById(android.R.id.content).apply { + setPadding(5, 6, 7, 8) + } + + EdgeToEdgeHelper.applyToAppBarLayout(activity, toolbar, STATUS_BAR_COLOR) + dispatchInsets(contentRoot) + dispatchInsets(appBarLayout) + + assertThat(appBarLayout.paddingLeft).isEqualTo(1) + assertThat(appBarLayout.paddingTop).isEqualTo(27) + assertThat(appBarLayout.paddingRight).isEqualTo(3) + assertThat(appBarLayout.paddingBottom).isEqualTo(4) + assertThat(contentRoot.paddingLeft).isEqualTo(20) + assertThat(contentRoot.paddingTop).isEqualTo(6) + assertThat(contentRoot.paddingRight).isEqualTo(42) + assertThat(contentRoot.paddingBottom).isEqualTo(48) + assertThat(appBarLayout.backgroundColor).isEqualTo(expectedStatusBarColor(activity)) + assertThat(toolbar.backgroundColor).isEqualTo(Color.RED) + + dispatchInsets(contentRoot) + dispatchInsets(appBarLayout) + + assertThat(appBarLayout.paddingTop).isEqualTo(27) + assertThat(contentRoot.paddingBottom).isEqualTo(48) + } + } + + @Test + fun testApplyToToolbarContainer_constraintParent_preservesToolbarColorAndConstraintsSpacer() { + launchTestActivity { activity -> + val root = ConstraintLayout(activity) + val toolbar = Toolbar(activity).apply { + id = View.generateViewId() + setBackgroundColor(Color.RED) + } + root.addView(toolbar, ConstraintLayout.LayoutParams(0, 56)) + ConstraintSet().apply { + clone(root) + connect(toolbar.id, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP) + connect(toolbar.id, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START) + connect(toolbar.id, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END) + applyTo(root) + } + activity.setContentView(root) + + EdgeToEdgeHelper.applyToToolbarContainer(activity, toolbar, STATUS_BAR_COLOR) + EdgeToEdgeHelper.applyToToolbarContainer(activity, toolbar, STATUS_BAR_COLOR) + val spacer = root.getChildAt(1) + dispatchInsets(spacer) + + assertThat(root.childCount).isEqualTo(2) + assertThat(toolbar.backgroundColor).isEqualTo(Color.RED) + assertThat(spacer.backgroundColor).isEqualTo(expectedStatusBarColor(activity)) + assertThat(spacer.layoutParams.height).isEqualTo(25) + assertThat((toolbar.layoutParams as ConstraintLayout.LayoutParams).topToBottom) + .isEqualTo(spacer.id) + } + } + + @Test + fun testApplyToToolbarContainer_genericParent_usesOverlayAndPreservesToolbarColorAndMargin() { + launchTestActivity { activity -> + val root = FrameLayout(activity) + val toolbar = Toolbar(activity).apply { setBackgroundColor(Color.RED) } + root.addView( + toolbar, + FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + 56 + ).apply { topMargin = 7 } + ) + activity.setContentView(root) + val contentRoot = activity.findViewById(android.R.id.content) + + EdgeToEdgeHelper.applyToToolbarContainer(activity, toolbar, STATUS_BAR_COLOR) + EdgeToEdgeHelper.applyToToolbarContainer(activity, toolbar, STATUS_BAR_COLOR) + val spacer = contentRoot.getChildAt(1) + dispatchInsets(spacer) + + assertThat(contentRoot.childCount).isEqualTo(2) + assertThat(toolbar.backgroundColor).isEqualTo(Color.RED) + assertThat(spacer.backgroundColor).isEqualTo(expectedStatusBarColor(activity)) + assertThat(spacer.layoutParams.height).isEqualTo(25) + assertThat((toolbar.layoutParams as FrameLayout.LayoutParams).topMargin).isEqualTo(32) + + dispatchInsets(spacer) + + assertThat((toolbar.layoutParams as FrameLayout.LayoutParams).topMargin).isEqualTo(32) + } + } + + @Test + fun testApplyToNavigationDrawer_ltrAndRtl_preservesPaddingAndCreatesOneSpacer() { + launchTestActivity { activity -> + val drawerRoot = FrameLayout(activity).apply { setPadding(1, 2, 3, 4) } + val drawerContent = LinearLayout(activity).apply { + addView(View(activity)) + } + val navigationView = View(activity).apply { fitsSystemWindows = true } + + EdgeToEdgeHelper.applyToNavigationDrawer( + activity, drawerRoot, drawerContent, navigationView, STATUS_BAR_COLOR + ) + EdgeToEdgeHelper.applyToNavigationDrawer( + activity, drawerRoot, drawerContent, navigationView, STATUS_BAR_COLOR + ) + ViewCompat.setLayoutDirection(drawerRoot, ViewCompat.LAYOUT_DIRECTION_LTR) + dispatchInsets(drawerRoot) + dispatchInsets(drawerContent) + + assertThat(drawerContent.childCount).isEqualTo(2) + assertThat(drawerContent.getChildAt(0).layoutParams.height).isEqualTo(25) + assertThat(drawerRoot.paddingLeft).isEqualTo(16) + assertThat(drawerRoot.paddingTop).isEqualTo(2) + assertThat(drawerRoot.paddingRight).isEqualTo(3) + assertThat(drawerRoot.paddingBottom).isEqualTo(44) + assertThat(navigationView.fitsSystemWindows).isFalse() + + ViewCompat.setLayoutDirection(drawerRoot, ViewCompat.LAYOUT_DIRECTION_RTL) + dispatchInsets(drawerRoot) + + assertThat(drawerRoot.paddingLeft).isEqualTo(1) + assertThat(drawerRoot.paddingRight).isEqualTo(38) + assertThat(drawerRoot.paddingBottom).isEqualTo(44) + } + } + + @Test + fun testApplyToRootConstraintLayout_twice_reusesSpacerAndPreservesPadding() { + launchTestActivity { activity -> + val root = ConstraintLayout(activity).apply { + setPadding(1, 2, 3, 4) + } + activity.setContentView(root) + val contentRoot = activity.findViewById(android.R.id.content) + + val firstSpacer = EdgeToEdgeHelper.applyToRootConstraintLayout( + activity, + root, + STATUS_BAR_COLOR, + statusBarLight = true + ) + val secondSpacer = EdgeToEdgeHelper.applyToRootConstraintLayout( + activity, + UPDATED_STATUS_BAR_COLOR, + statusBarLight = true + ) + dispatchInsets(root) + dispatchInsets(secondSpacer) + + assertThat(contentRoot.childCount).isEqualTo(2) + assertThat(secondSpacer).isSameInstanceAs(firstSpacer) + assertThat(secondSpacer.backgroundColor) + .isEqualTo(ContextCompat.getColor(activity, UPDATED_STATUS_BAR_COLOR)) + assertThat(secondSpacer.layoutParams.height).isEqualTo(25) + assertThat(root.paddingLeft).isEqualTo(16) + assertThat(root.paddingTop).isEqualTo(27) + assertThat(root.paddingRight).isEqualTo(38) + assertThat(root.paddingBottom).isEqualTo(44) + + dispatchInsets(root) + dispatchInsets(secondSpacer) + + assertThat(root.paddingLeft).isEqualTo(16) + assertThat(root.paddingTop).isEqualTo(27) + assertThat(root.paddingRight).isEqualTo(38) + assertThat(root.paddingBottom).isEqualTo(44) + } + } + + @Test + fun testEnableEdgeToEdgeDispatch_doesNotCrash() { + launchTestActivity(EdgeToEdgeHelper::enableEdgeToEdgeDispatch) + } + + private fun launchTestActivity(testBlock: (AppCompatActivity) -> Unit) { + ActivityScenario.launch(AppCompatActivity::class.java).use { scenario -> + scenario.onActivity(testBlock) + } + } + + private fun dispatchInsets(view: View) { + ViewCompat.dispatchApplyWindowInsets(view, TEST_INSETS) + } + + private fun expectedStatusBarColor(activity: AppCompatActivity): Int = + ContextCompat.getColor(activity, STATUS_BAR_COLOR) + + private val View.backgroundColor: Int + get() = (background as ColorDrawable).color + + private companion object { + val STATUS_BAR_COLOR = R.color.component_color_shared_activity_status_bar_color + val UPDATED_STATUS_BAR_COLOR = R.color.component_color_shared_profile_status_bar_color + + val TEST_INSETS: WindowInsetsCompat = WindowInsetsCompat.Builder() + .setInsets(WindowInsetsCompat.Type.systemBars(), Insets.of(10, 20, 30, 40)) + .setInsets(WindowInsetsCompat.Type.displayCutout(), Insets.of(15, 25, 35, 0)) + .build() + } +}