diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c04229afc00..547b13fc3a6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -18,6 +18,7 @@
+
diff --git a/app/src/main/java/org/oppia/app/activity/ActivityComponent.kt b/app/src/main/java/org/oppia/app/activity/ActivityComponent.kt
index 62540489a0b..1038aecf0ba 100644
--- a/app/src/main/java/org/oppia/app/activity/ActivityComponent.kt
+++ b/app/src/main/java/org/oppia/app/activity/ActivityComponent.kt
@@ -9,6 +9,7 @@ import org.oppia.app.player.audio.testing.AudioFragmentTestActivity
import org.oppia.app.player.exploration.ExplorationActivity
import org.oppia.app.topic.conceptcard.testing.ConceptCardFragmentTestActivity
import org.oppia.app.player.state.testing.StateFragmentTestActivity
+import org.oppia.app.profile.ProfileActivity
import org.oppia.app.testing.BindableAdapterTestActivity
import org.oppia.app.topic.TopicActivity
import org.oppia.app.topic.questionplayer.QuestionPlayerActivity
@@ -34,4 +35,5 @@ interface ActivityComponent {
fun inject(topicActivity: TopicActivity)
fun inject(audioFragmentTestActivity: AudioFragmentTestActivity)
fun inject(stateFragmentTestActivity: StateFragmentTestActivity)
+ fun inject(profileActivity: ProfileActivity)
}
diff --git a/app/src/main/java/org/oppia/app/fragment/FragmentComponent.kt b/app/src/main/java/org/oppia/app/fragment/FragmentComponent.kt
index e6a01426435..e982ef2160f 100644
--- a/app/src/main/java/org/oppia/app/fragment/FragmentComponent.kt
+++ b/app/src/main/java/org/oppia/app/fragment/FragmentComponent.kt
@@ -7,6 +7,9 @@ import org.oppia.app.home.HomeFragment
import org.oppia.app.player.exploration.ExplorationFragment
import org.oppia.app.player.state.StateFragment
import org.oppia.app.player.audio.AudioFragment
+import org.oppia.app.profile.AddProfileFragment
+import org.oppia.app.profile.AdminAuthFragment
+import org.oppia.app.profile.ProfileChooserFragment
import org.oppia.app.testing.BindableAdapterTestFragment
import org.oppia.app.topic.TopicFragment
import org.oppia.app.topic.conceptcard.ConceptCardFragment
@@ -38,4 +41,7 @@ interface FragmentComponent {
fun inject(topicPlayFragment: TopicPlayFragment)
fun inject(topicReviewFragment: TopicReviewFragment)
fun inject(topicTrainFragment: TopicTrainFragment)
+ fun inject(profileChooserFragment: ProfileChooserFragment)
+ fun inject(adminAuthFragment: AdminAuthFragment)
+ fun inject(addProfileFragment: AddProfileFragment)
}
diff --git a/app/src/main/java/org/oppia/app/profile/AddProfileFragment.kt b/app/src/main/java/org/oppia/app/profile/AddProfileFragment.kt
new file mode 100644
index 00000000000..8551a091f77
--- /dev/null
+++ b/app/src/main/java/org/oppia/app/profile/AddProfileFragment.kt
@@ -0,0 +1,23 @@
+package org.oppia.app.profile
+
+import android.content.Context
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import org.oppia.app.fragment.InjectableFragment
+import javax.inject.Inject
+
+/** Fragment that allows users to create new profiles. */
+class AddProfileFragment : InjectableFragment() {
+ @Inject lateinit var addProfileFragmentPresenter: AddProfileFragmentPresenter
+
+ override fun onAttach(context: Context?) {
+ super.onAttach(context)
+ fragmentComponent.inject(this)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ return addProfileFragmentPresenter.handleCreateView(inflater, container)
+ }
+}
diff --git a/app/src/main/java/org/oppia/app/profile/AddProfileFragmentPresenter.kt b/app/src/main/java/org/oppia/app/profile/AddProfileFragmentPresenter.kt
new file mode 100644
index 00000000000..262f347f9fc
--- /dev/null
+++ b/app/src/main/java/org/oppia/app/profile/AddProfileFragmentPresenter.kt
@@ -0,0 +1,20 @@
+package org.oppia.app.profile
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import org.oppia.app.databinding.AddProfileFragmentBinding
+import org.oppia.app.fragment.FragmentScope
+import javax.inject.Inject
+
+/** The presenter for [AddProfileFragment]. */
+@FragmentScope
+class AddProfileFragmentPresenter @Inject constructor(
+ private val fragment: Fragment
+) {
+ fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? {
+ val binding = AddProfileFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false)
+ return binding.root
+ }
+}
diff --git a/app/src/main/java/org/oppia/app/profile/AdminAuthFragment.kt b/app/src/main/java/org/oppia/app/profile/AdminAuthFragment.kt
new file mode 100644
index 00000000000..bdfc867d565
--- /dev/null
+++ b/app/src/main/java/org/oppia/app/profile/AdminAuthFragment.kt
@@ -0,0 +1,23 @@
+package org.oppia.app.profile
+
+import android.content.Context
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import org.oppia.app.fragment.InjectableFragment
+import javax.inject.Inject
+
+/** Fragment that authenticates by checking for admin's PIN. */
+class AdminAuthFragment : InjectableFragment() {
+ @Inject lateinit var adminAuthFragmentPresenter: AdminAuthFragmentPresenter
+
+ override fun onAttach(context: Context?) {
+ super.onAttach(context)
+ fragmentComponent.inject(this)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ return adminAuthFragmentPresenter.handleCreateView(inflater, container)
+ }
+}
diff --git a/app/src/main/java/org/oppia/app/profile/AdminAuthFragmentPresenter.kt b/app/src/main/java/org/oppia/app/profile/AdminAuthFragmentPresenter.kt
new file mode 100644
index 00000000000..fb6b6d6986b
--- /dev/null
+++ b/app/src/main/java/org/oppia/app/profile/AdminAuthFragmentPresenter.kt
@@ -0,0 +1,21 @@
+package org.oppia.app.profile
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import org.oppia.app.databinding.AdminAuthFragmentBinding
+import org.oppia.app.fragment.FragmentScope
+import javax.inject.Inject
+
+/** The presenter for [AdminAuthFragment]. */
+@FragmentScope
+class AdminAuthFragmentPresenter @Inject constructor(
+ private val fragment: Fragment
+) {
+ fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? {
+ val binding = AdminAuthFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false)
+ return binding.root
+ }
+}
diff --git a/app/src/main/java/org/oppia/app/profile/ProfileActivity.kt b/app/src/main/java/org/oppia/app/profile/ProfileActivity.kt
new file mode 100644
index 00000000000..0fe0b3eb850
--- /dev/null
+++ b/app/src/main/java/org/oppia/app/profile/ProfileActivity.kt
@@ -0,0 +1,16 @@
+package org.oppia.app.profile
+
+import android.os.Bundle
+import org.oppia.app.activity.InjectableAppCompatActivity
+import javax.inject.Inject
+
+/** Activity that controls profile creation and selection. */
+class ProfileActivity : InjectableAppCompatActivity() {
+ @Inject lateinit var profileActivityPresenter: ProfileActivityPresenter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ activityComponent.inject(this)
+ profileActivityPresenter.handleOnCreate()
+ }
+}
diff --git a/app/src/main/java/org/oppia/app/profile/ProfileActivityPresenter.kt b/app/src/main/java/org/oppia/app/profile/ProfileActivityPresenter.kt
new file mode 100644
index 00000000000..ac67141bcb0
--- /dev/null
+++ b/app/src/main/java/org/oppia/app/profile/ProfileActivityPresenter.kt
@@ -0,0 +1,24 @@
+package org.oppia.app.profile
+
+import androidx.appcompat.app.AppCompatActivity
+import org.oppia.app.R
+import org.oppia.app.activity.ActivityScope
+import javax.inject.Inject
+
+/** The presenter for [ProfileActivity]. */
+@ActivityScope
+class ProfileActivityPresenter @Inject constructor(private val activity: AppCompatActivity){
+ fun handleOnCreate() {
+ activity.setContentView(R.layout.profile_activity)
+ if (getProfileChooserFragment() == null) {
+ activity.supportFragmentManager.beginTransaction().add(
+ R.id.profile_chooser_fragment_placeholder,
+ ProfileChooserFragment()
+ ).commitNow()
+ }
+ }
+
+ private fun getProfileChooserFragment(): ProfileChooserFragment? {
+ return activity.supportFragmentManager.findFragmentById(R.id.profile_chooser_fragment_placeholder) as ProfileChooserFragment?
+ }
+}
diff --git a/app/src/main/java/org/oppia/app/profile/ProfileChooserFragment.kt b/app/src/main/java/org/oppia/app/profile/ProfileChooserFragment.kt
new file mode 100644
index 00000000000..c87e270732f
--- /dev/null
+++ b/app/src/main/java/org/oppia/app/profile/ProfileChooserFragment.kt
@@ -0,0 +1,23 @@
+package org.oppia.app.profile
+
+import android.content.Context
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import org.oppia.app.fragment.InjectableFragment
+import javax.inject.Inject
+
+/** Fragment that allows user to select a profile or create new ones. */
+class ProfileChooserFragment : InjectableFragment() {
+ @Inject lateinit var profileChooserFragmentPresenter: ProfileChooserFragmentPresenter
+
+ override fun onAttach(context: Context?) {
+ super.onAttach(context)
+ fragmentComponent.inject(this)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ return profileChooserFragmentPresenter.handleCreateView(inflater, container)
+ }
+}
diff --git a/app/src/main/java/org/oppia/app/profile/ProfileChooserFragmentPresenter.kt b/app/src/main/java/org/oppia/app/profile/ProfileChooserFragmentPresenter.kt
new file mode 100644
index 00000000000..fe7736607eb
--- /dev/null
+++ b/app/src/main/java/org/oppia/app/profile/ProfileChooserFragmentPresenter.kt
@@ -0,0 +1,30 @@
+package org.oppia.app.profile
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import org.oppia.app.databinding.ProfileChooserFragmentBinding
+import org.oppia.app.fragment.FragmentScope
+import org.oppia.app.viewmodel.ViewModelProvider
+import javax.inject.Inject
+
+/** The presenter for [ProfileChooserFragment]. */
+@FragmentScope
+class ProfileChooserFragmentPresenter @Inject constructor(
+ private val fragment: Fragment,
+ private val viewModelProvider: ViewModelProvider
+) {
+ fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? {
+ val binding = ProfileChooserFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false)
+ binding.apply {
+ viewModel = getProfileChooserViewModel()
+ }
+ return binding.root
+ }
+
+ private fun getProfileChooserViewModel(): ProfileChooserViewModel {
+ return viewModelProvider.getForFragment(fragment, ProfileChooserViewModel::class.java)
+ }
+}
diff --git a/app/src/main/java/org/oppia/app/profile/ProfileChooserViewModel.kt b/app/src/main/java/org/oppia/app/profile/ProfileChooserViewModel.kt
new file mode 100644
index 00000000000..22bbfc5dc43
--- /dev/null
+++ b/app/src/main/java/org/oppia/app/profile/ProfileChooserViewModel.kt
@@ -0,0 +1,11 @@
+package org.oppia.app.profile
+
+import androidx.lifecycle.ViewModel
+import org.oppia.app.fragment.FragmentScope
+import org.oppia.app.viewmodel.ObservableViewModel
+import javax.inject.Inject
+
+/** The ViewModel for [ProfileChooserFragment]. */
+@FragmentScope
+class ProfileChooserViewModel @Inject constructor(): ObservableViewModel() {
+}
diff --git a/app/src/main/res/layout/add_profile_fragment.xml b/app/src/main/res/layout/add_profile_fragment.xml
new file mode 100644
index 00000000000..acae5072cd2
--- /dev/null
+++ b/app/src/main/res/layout/add_profile_fragment.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/admin_auth_fragment.xml b/app/src/main/res/layout/admin_auth_fragment.xml
new file mode 100644
index 00000000000..8bcad6e3107
--- /dev/null
+++ b/app/src/main/res/layout/admin_auth_fragment.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/profile_activity.xml b/app/src/main/res/layout/profile_activity.xml
new file mode 100644
index 00000000000..d4018d0171a
--- /dev/null
+++ b/app/src/main/res/layout/profile_activity.xml
@@ -0,0 +1,8 @@
+
+
diff --git a/app/src/main/res/layout/profile_chooser_fragment.xml b/app/src/main/res/layout/profile_chooser_fragment.xml
new file mode 100644
index 00000000000..cf4d05e6319
--- /dev/null
+++ b/app/src/main/res/layout/profile_chooser_fragment.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+