diff --git a/mailbox-android/src/main/AndroidManifest.xml b/mailbox-android/src/main/AndroidManifest.xml
index 30bcdd515ab75017ad760198f5ecfed04d71b2bf..84f503a7181790a82856f0ab9be5e433104d6370 100644
--- a/mailbox-android/src/main/AndroidManifest.xml
+++ b/mailbox-android/src/main/AndroidManifest.xml
@@ -22,8 +22,6 @@
         android:supportsRtl="true"
         android:theme="@style/Theme.BriarMailbox">
 
-        <service android:name=".android.MailboxService" />
-
         <activity
             android:name=".android.ui.MainActivity"
             android:exported="true"
@@ -34,14 +32,29 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <activity
+            android:name=".android.ui.settings.SettingsActivity"
+            android:exported="false"
+            android:label="@string/prefs_title" />
         <activity
             android:name=".android.ui.WipeCompleteActivity"
             android:excludeFromRecents="true"
             android:launchMode="singleInstance"
-            android:process=":briar_mailbox_wipe_complete" />
+            android:process=":briar_mailbox_wipe_complete"
+            android:theme="@style/Theme.BriarMailbox.NoActionBar" />
+        <activity
+            android:name=".android.ui.StartupFailureActivity"
+            android:excludeFromRecents="true"
+            android:exported="false"
+            android:finishOnTaskLaunch="true"
+            android:label="@string/startup_failed_activity_title"
+            android:launchMode="singleInstance"
+            android:process=":briar_mailbox_startup_failure"
+            android:theme="@style/Theme.BriarMailbox.NoActionBar" />
 
-        <receiver android:name=".core.system.AlarmReceiver" />
+        <service android:name=".android.MailboxService" />
 
+        <receiver android:name=".core.system.AlarmReceiver" />
         <receiver
             android:name=".android.StartReceiver"
             android:exported="false">
@@ -50,15 +63,6 @@
                 <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
             </intent-filter>
         </receiver>
-
-        <activity
-            android:name=".android.ui.StartupFailureActivity"
-            android:excludeFromRecents="true"
-            android:exported="false"
-            android:finishOnTaskLaunch="true"
-            android:label="@string/startup_failed_activity_title"
-            android:launchMode="singleInstance"
-            android:process=":briar_mailbox_startup_failure" />
     </application>
 
-</manifest>
+</manifest>
\ No newline at end of file
diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/MainActivity.kt b/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/MainActivity.kt
index fb99d10f6622c005c622ff8e6757df693e19aec4..86fc899458490504c0f4b2a99a03a3c2d0dd5f1c 100644
--- a/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/MainActivity.kt
+++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/MainActivity.kt
@@ -23,12 +23,18 @@ import android.Manifest.permission.POST_NOTIFICATIONS
 import android.content.Intent
 import android.os.Build.VERSION.SDK_INT
 import android.os.Bundle
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
 import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
 import androidx.activity.viewModels
+import androidx.annotation.UiThread
 import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.app.AppCompatActivity
 import androidx.core.content.PermissionChecker.PERMISSION_GRANTED
 import androidx.core.content.PermissionChecker.checkSelfPermission
+import androidx.core.view.MenuProvider
+import androidx.lifecycle.Lifecycle.State.RESUMED
 import androidx.navigation.NavController
 import androidx.navigation.fragment.NavHostFragment
 import dagger.hilt.android.AndroidEntryPoint
@@ -57,12 +63,13 @@ import org.briarproject.mailbox.android.StatusManager.Stopped
 import org.briarproject.mailbox.android.StatusManager.Stopping
 import org.briarproject.mailbox.android.StatusManager.Undecided
 import org.briarproject.mailbox.android.StatusManager.Wiping
+import org.briarproject.mailbox.android.ui.settings.SettingsActivity
 import org.briarproject.mailbox.core.lifecycle.LifecycleManager.LifecycleState.NOT_STARTED
 import org.briarproject.mailbox.core.util.LogUtils.info
 import org.slf4j.LoggerFactory.getLogger
 
 @AndroidEntryPoint
-class MainActivity : AppCompatActivity() {
+class MainActivity : AppCompatActivity(), MenuProvider {
 
     companion object {
         private val LOG = getLogger(MainActivity::class.java)
@@ -87,6 +94,8 @@ class MainActivity : AppCompatActivity() {
         LOG.info("onCreate()")
         setContentView(R.layout.activity_main)
 
+        addMenuProvider(this, this, RESUMED)
+
         LOG.info { "do we have a saved instance state? " + (savedInstanceState != null) }
         hadBeenStartedOnSave =
             savedInstanceState?.getBoolean(BUNDLE_LIFECYCLE_HAS_STARTED) ?: false
@@ -111,6 +120,19 @@ class MainActivity : AppCompatActivity() {
         }
     }
 
+    override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
+        menuInflater.inflate(R.menu.main_actions, menu)
+    }
+
+    override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
+        if (menuItem.itemId == R.id.action_settings) {
+            startActivity(Intent(this, SettingsActivity::class.java))
+            return true
+        }
+        return false
+    }
+
+    @UiThread
     private fun onAppStateChanged(state: MailboxAppState) {
         // Catch the situation where we come back to the activity after a remote wipe has happened
         // while the app was in the background and gets restored from the recent app list after
@@ -122,21 +144,20 @@ class MainActivity : AppCompatActivity() {
             startActivity(Intent(this, WipeCompleteActivity::class.java))
             return
         }
+        val currentDestId = nav.currentDestination?.id
         when (state) {
             Undecided -> supportActionBar?.hide() // hide action bar until we need it
-            NeedOnboarding -> {
+            NeedOnboarding -> if (currentDestId == R.id.initFragment) {
                 supportActionBar?.hide()
-                if (nav.currentDestination?.id == R.id.initFragment)
-                    nav.navigate(actionGlobalOnboardingContainer())
+                nav.navigate(actionGlobalOnboardingContainer())
             }
-            NeedsDozeExemption -> {
+            NeedsDozeExemption -> if (currentDestId != R.id.doNotKillMeFragment) {
                 supportActionBar?.hide()
-                if (nav.currentDestination?.id != R.id.doNotKillMeFragment)
-                    nav.navigate(actionGlobalDoNotKillMeFragment())
+                nav.navigate(actionGlobalDoNotKillMeFragment())
             }
             NotStarted -> {
                 askForNotificationPermission()
-                supportActionBar?.hide()
+                supportActionBar?.show()
                 nav.navigate(actionGlobalStartupFragment())
             }
             // It is important to navigate here from various fragments. The normal case is
@@ -144,47 +165,40 @@ class MainActivity : AppCompatActivity() {
             // However, when the service got killed and the app has been restored with a different
             // UI state such as the qr code screen or the status screen, then we also want to
             // navigate to the startup fragment.
-            is Starting -> {
-                supportActionBar?.hide()
-                if (nav.currentDestination?.id != R.id.startupFragment)
-                    nav.navigate(actionGlobalStartupFragment())
+            is Starting -> if (currentDestId != R.id.startupFragment) {
+                supportActionBar?.show()
+                nav.navigate(actionGlobalStartupFragment())
             }
-            is StartedSettingUp -> {
+            is StartedSettingUp -> if (currentDestId != R.id.qrCodeFragment &&
+                currentDestId != R.id.qrCodeLinkFragment
+            ) {
                 supportActionBar?.show()
-                if (nav.currentDestination?.id != R.id.qrCodeFragment &&
-                    nav.currentDestination?.id != R.id.qrCodeLinkFragment
-                ) nav.navigate(actionGlobalQrCodeFragment())
+                nav.navigate(actionGlobalQrCodeFragment())
             }
-            StartedSetupComplete -> {
-                if (nav.currentDestination?.id == R.id.qrCodeFragment) {
-                    supportActionBar?.hide()
-                    nav.navigate(actionGlobalSetupCompleteFragment())
-                } else if (nav.currentDestination?.id != R.id.statusFragment &&
-                    nav.currentDestination?.id != R.id.setupCompleteFragment
-                ) {
-                    supportActionBar?.show()
-                    nav.navigate(actionGlobalStatusFragment())
-                }
+            StartedSetupComplete -> if (currentDestId == R.id.qrCodeFragment) {
+                supportActionBar?.hide()
+                nav.navigate(actionGlobalSetupCompleteFragment())
+            } else if (currentDestId != R.id.statusFragment &&
+                currentDestId != R.id.setupCompleteFragment
+            ) {
+                supportActionBar?.show()
+                nav.navigate(actionGlobalStatusFragment())
             }
-            ErrorNoNetwork -> {
+            ErrorNoNetwork -> if (currentDestId != R.id.noNetworkFragment) {
                 supportActionBar?.hide()
-                if (nav.currentDestination?.id != R.id.noNetworkFragment)
-                    nav.navigate(actionGlobalNoNetworkFragment())
+                nav.navigate(actionGlobalNoNetworkFragment())
             }
-            ErrorClockSkew -> {
+            ErrorClockSkew -> if (currentDestId != R.id.clockSkewFragment) {
                 supportActionBar?.hide()
-                if (nav.currentDestination?.id != R.id.clockSkewFragment)
-                    nav.navigate(actionGlobalClockSkewFragment())
+                nav.navigate(actionGlobalClockSkewFragment())
             }
-            Stopping -> {
+            Stopping -> if (currentDestId != R.id.stoppingFragment) {
                 supportActionBar?.hide()
-                if (nav.currentDestination?.id != R.id.stoppingFragment)
-                    nav.navigate(actionGlobalStoppingFragment())
+                nav.navigate(actionGlobalStoppingFragment())
             }
-            Wiping -> {
+            Wiping -> if (nav.currentDestination?.id != R.id.wipingFragment) {
                 supportActionBar?.hide()
-                if (nav.currentDestination?.id != R.id.wipingFragment)
-                    nav.navigate(actionGlobalWipingFragment())
+                nav.navigate(actionGlobalWipingFragment())
             }
             Stopped -> {} // nothing to do but needs to be exhaustive for Kotlin 1.7
         }
diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/settings/SettingsActivity.kt b/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/settings/SettingsActivity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b81c7bf49687ee665a9c909fa834d35850c252bc
--- /dev/null
+++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/settings/SettingsActivity.kt
@@ -0,0 +1,41 @@
+package org.briarproject.mailbox.android.ui.settings
+
+import android.os.Bundle
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
+import androidx.annotation.CallSuper
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.MenuProvider
+import androidx.lifecycle.Lifecycle.State.RESUMED
+import dagger.hilt.android.AndroidEntryPoint
+import org.briarproject.mailbox.databinding.ActivitySettingsBinding
+
+@AndroidEntryPoint
+class SettingsActivity : AppCompatActivity(), MenuProvider {
+
+    private lateinit var binding: ActivitySettingsBinding
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        binding = ActivitySettingsBinding.inflate(layoutInflater)
+        setContentView(binding.root)
+
+        // only needed for up/back navigation in action bar
+        addMenuProvider(this, this, RESUMED)
+        supportActionBar?.setDisplayHomeAsUpEnabled(true)
+    }
+
+    override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
+    }
+
+    @CallSuper
+    override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
+        if (menuItem.itemId == android.R.id.home) {
+            onBackPressedDispatcher.onBackPressed()
+            return true
+        }
+        return false
+    }
+}
diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/settings/SettingsFragment.kt b/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/settings/SettingsFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..17c386bb4fe8e168c598626febb7a3607ed182d0
--- /dev/null
+++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/settings/SettingsFragment.kt
@@ -0,0 +1,19 @@
+package org.briarproject.mailbox.android.ui.settings
+
+import android.os.Bundle
+import androidx.fragment.app.activityViewModels
+import androidx.preference.PreferenceFragmentCompat
+import dagger.hilt.android.AndroidEntryPoint
+import org.briarproject.mailbox.R
+import org.briarproject.mailbox.android.ui.MailboxViewModel
+
+@AndroidEntryPoint
+class SettingsFragment : PreferenceFragmentCompat() {
+
+    private val viewModel: MailboxViewModel by activityViewModels()
+
+    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+        setPreferencesFromResource(R.xml.preferences, rootKey)
+    }
+
+}
diff --git a/mailbox-android/src/main/res/layout/activity_settings.xml b/mailbox-android/src/main/res/layout/activity_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ccd386d2e631617c3e1bb618572ef5773eb09196
--- /dev/null
+++ b/mailbox-android/src/main/res/layout/activity_settings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/fragmentContainer"
+    android:name="org.briarproject.mailbox.android.ui.settings.SettingsFragment"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".android.ui.settings.SettingsActivity" />
diff --git a/mailbox-android/src/main/res/menu/main_actions.xml b/mailbox-android/src/main/res/menu/main_actions.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ff816139fee668d8d7e7844eeff36d7194ddce34
--- /dev/null
+++ b/mailbox-android/src/main/res/menu/main_actions.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <item
+        android:id="@+id/action_settings"
+        android:title="@string/prefs_title"
+        app:showAsAction="never" />
+</menu>
diff --git a/mailbox-android/src/main/res/values/strings.xml b/mailbox-android/src/main/res/values/strings.xml
index d6cdf41f190048688dd6d2ebfa62f90e0b0854fb..db8d0c7ffafce946455050fccf7f24b9e7aa3e8f 100644
--- a/mailbox-android/src/main/res/values/strings.xml
+++ b/mailbox-android/src/main/res/values/strings.xml
@@ -79,4 +79,17 @@
     <string name="startup_failed_lifecycle_reuse">Mailbox has already stopped.\n\nPlease close the app and try again.</string>
     <string name="startup_failed_clock_error">Mailbox was unable to start because your device\'s clock is wrong.\n\nPlease set your device\'s clock to the right time and try again.</string>
 
+    <!-- Preference -->
+    <string name="prefs_title">Settings</string>
+    <string name="prefs_tor_category_title">Tor circumvention settings</string>
+    <string name="prefs_tor_auto_title">Automatic bridge selection</string>
+    <string name="prefs_tor_auto_summary">Bridges get chosen based on your location</string>
+    <string name="prefs_tor_bridges_title">Use bridges</string>
+    <string name="prefs_bridges_category_title">Bridge types</string>
+    <string name="prefs_bridges_snowflake_title">Snowflake</string>
+    <string name="prefs_bridges_vanilla_title">Vanilla</string>
+    <string name="prefs_bridges_obfs4_title">Obfs4</string>
+    <string name="prefs_bridges_obfs_builtin_title">Obfs4 from Tor Browser</string>
+    <string name="prefs_bridges_meek_title">Meek</string>
+
 </resources>
diff --git a/mailbox-android/src/main/res/values/themes.xml b/mailbox-android/src/main/res/values/themes.xml
index 892878df15c459ee8d1946233793b8365691433f..1f8f089329e8268de6d91a5b6444067bef1bd513 100644
--- a/mailbox-android/src/main/res/values/themes.xml
+++ b/mailbox-android/src/main/res/values/themes.xml
@@ -19,4 +19,10 @@
     <style name="Theme.BriarMailbox.Dialog.Destructive" parent="Theme.BriarMailbox.Dialog">
         <item name="buttonBarPositiveButtonStyle">@style/TextButtonDestructive</item>
     </style>
+
+    <style name="Theme.BriarMailbox.NoActionBar" parent="Theme.BriarMailboxBase">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+    </style>
+
 </resources>
diff --git a/mailbox-android/src/main/res/xml/preferences.xml b/mailbox-android/src/main/res/xml/preferences.xml
new file mode 100644
index 0000000000000000000000000000000000000000..16929e09e32360020710017ffc587ea37f93a245
--- /dev/null
+++ b/mailbox-android/src/main/res/xml/preferences.xml
@@ -0,0 +1,65 @@
+<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <PreferenceCategory
+        app:iconSpaceReserved="false"
+        app:title="@string/prefs_tor_category_title">
+
+        <SwitchPreferenceCompat
+            app:defaultValue="true"
+            app:disableDependentsState="true"
+            app:iconSpaceReserved="false"
+            app:key="pref_auto"
+            app:summary="@string/prefs_tor_auto_summary"
+            app:title="@string/prefs_tor_auto_title" />
+
+        <SwitchPreferenceCompat
+            app:defaultValue="false"
+            app:dependency="pref_auto"
+            app:iconSpaceReserved="false"
+            app:key="pref_use_bridges"
+            app:title="@string/prefs_tor_bridges_title" />
+
+    </PreferenceCategory>
+
+    <PreferenceCategory
+        app:iconSpaceReserved="false"
+        app:title="@string/prefs_bridges_category_title">
+
+        <SwitchPreferenceCompat
+            app:defaultValue="false"
+            app:dependency="pref_use_bridges"
+            app:iconSpaceReserved="false"
+            app:key="pref_bridges_snowflake"
+            app:title="@string/prefs_bridges_snowflake_title" />
+
+        <SwitchPreferenceCompat
+            app:defaultValue="false"
+            app:dependency="pref_use_bridges"
+            app:iconSpaceReserved="false"
+            app:key="pref_bridges_meek"
+            app:title="@string/prefs_bridges_meek_title" />
+
+        <SwitchPreferenceCompat
+            app:defaultValue="false"
+            app:dependency="pref_use_bridges"
+            app:iconSpaceReserved="false"
+            app:key="pref_bridges_obfs4"
+            app:title="@string/prefs_bridges_obfs4_title" />
+
+        <SwitchPreferenceCompat
+            app:defaultValue="false"
+            app:dependency="pref_use_bridges"
+            app:iconSpaceReserved="false"
+            app:key="pref_bridges_obfs_builtin"
+            app:title="@string/prefs_bridges_obfs_builtin_title" />
+
+        <SwitchPreferenceCompat
+            app:defaultValue="false"
+            app:dependency="pref_use_bridges"
+            app:iconSpaceReserved="false"
+            app:key="pref_bridges_vanilla"
+            app:title="@string/prefs_bridges_vanilla_title" />
+
+    </PreferenceCategory>
+
+</PreferenceScreen>